Ciao, e benvenuto nella sesta puntata della sessantottesima stagione. Nella puntata scorsa abbiamo visto cosa succede quando le regole tacciono, e il programma si incastra. Oggi guardiamo la situazione opposta e altrettanto insidiosa: cosa succede quando le regole, invece di tacere, dicono troppo. Quando da una stessa situazione permettono più di una mossa, e non stabiliscono quale. È il mondo del non-determinismo.
Partiamo dal caso più semplice, che ti riguarda anche se non fai nulla di parallelo: l'ordine in cui si valutano le cose. Immagina un'operazione che combina due pezzi, e ognuno dei due, per essere calcolato, richiede a sua volta del lavoro. Quale dei due si calcola per primo? A volte il linguaggio lo stabilisce con precisione: prima questo, poi quello, sempre. Ma altri linguaggi, di proposito, non lo dicono. Lasciano libera l'implementazione di scegliere l'ordine che preferisce. Finché i due calcoli sono indipendenti, non cambia nulla. Ma se uno dei due, di nascosto, influenza l'altro, allora il risultato dipende dall'ordine, e l'ordine non è garantito.
Vediamo perché questo è una trappola sottile. Quel codice, sulla tua macchina, con il tuo strumento, funziona benissimo. Gira mille volte e dà sempre lo stesso risultato. Poi cambi compilatore, o versione, o macchina, e improvvisamente il risultato è diverso. Non hai toccato niente, eppure si comporta in un altro modo. Non è un bug dello strumento: è che il tuo codice si appoggiava a un ordine che il linguaggio non aveva mai promesso. Le regole lasciavano scegliere, e prima veniva scelto un ordine, ora un altro. Ti eri fidato di una regolarità che non era una regola. E questa, come vedremo alla fine, è una delle trappole più universali che esistano.
Ora saliamo di livello, al non-determinismo più famoso: quello di più cose che accadono insieme. Quando due flussi di esecuzione procedono in parallelo, condividendo qualcosa, i loro passi si intrecciano. Un passo dell'uno, poi uno dell'altro, poi ancora del primo, in un ordine che nessuno ha deciso in anticipo. Ogni intreccio possibile è un'esecuzione valida diversa. E qui il significato del programma smette di essere un unico film: diventa un ventaglio di film possibili, uno per ogni modo in cui i passi si possono alternare. Ne parlammo, di questo intreccio, quando affrontammo la concorrenza: ora vedi che ha una forma precisa dentro le regole di esecuzione: non è disordine misterioso, è semplicemente che le regole ammettono più intrecci, e ognuno è un cammino legale.
Nota la distinzione fine, ma cruciale, con la puntata scorsa. La scorsa volta le regole tacevano: nessuna mossa, e il programma si incastrava, senza significato. Oggi le regole parlano fin troppo: più mosse legali, e il programma ha tanti significati possibili, tutti validi. Sono due modi opposti in cui la certezza si perde. Nel primo caso non sai cosa succede perché non è definito niente. Nel secondo non sai cosa succede perché è definito troppo, e il risultato dipende da una scelta che non controlli. Sapere in quale dei due casi ti trovi è già metà della diagnosi.
C'è un'immagine che tiene insieme tutto, e resta nel mondo dei giochi. Pensa a un gioco in cui, da una certa posizione, il regolamento consente più mosse ugualmente legali, e non dice quale scegliere. Se giochi da solo, poco male: ne scegli una. Ma se la partita la conducono più giocatori che si alternano senza un ordine fisso, la stessa posizione di partenza può portare a partite completamente diverse. Non perché qualcuno bari, ma perché il regolamento lì lasciava aperte più strade. Il tuo programma concorrente è quel gioco a più mani.
Voglio darti la difesa pratica, perché non resti solo un allarme. La regola d'oro è: non appoggiarti mai a un ordine che il linguaggio non ti ha garantito. Se un pezzo di codice dà il risultato giusto solo per un certo intreccio dei passi, e un altro intreccio lo rovina, quel codice è fragile, anche se oggi funziona. La robustezza sta nello scrivere in modo che il risultato non dipenda da scelte che non controlli: rendere i pezzi davvero indipendenti, o mettere ordine esplicito dove l'ordine conta. Il non-determinismo non si combatte sperando che vada bene: si combatte togliendo al caso il potere di decidere.
Resta la lezione di fondo, e vale oltre il codice. Molti errori, nella vita e nel lavoro, nascono dal confondere una regolarità con una regola. Ha sempre funzionato così non vuol dire deve funzionare così. La prima è un'abitudine osservata, la seconda una garanzia. Chi costruisce cose solide impara a chiedersi, davanti a ogni regolarità comoda: è una promessa, o solo una fortuna che è durata finora? E costruisce sulle promesse, non sulle coincidenze.
Per oggi ci fermiamo qui. Abbiamo guardato l'opposto dello stallo: quando le regole, invece di tacere, lasciano scegliere. Il caso quotidiano è l'ordine di valutazione non garantito: finché i pezzi sono indipendenti va tutto bene, ma se uno influenza l'altro il risultato dipende da un ordine che il linguaggio non ha promesso. Il caso famoso è la concorrenza: più flussi che intrecciano i loro passi, e il significato diventa un ventaglio di film possibili. La distinzione con la scorsa volta: prima le regole tacevano e mancava il significato, oggi dicono troppo e i significati sono tanti. La difesa: non appoggiarti mai a un ordine che non ti è stato garantito. La lezione: non confondere una regolarità con una regola. Nella prossima puntata: la promessa dei tipi. Nelle note trovi qualche spunto. Se ti è utile, condividila. Grazie per l'ascolto, e ci sentiamo alla prossima.