Il vantaggio è che le funzioni pure rendono il codice più facile da ragionare. In altre parole, gli effetti collaterali aumentano la complessità del tuo codice.
Fai un esempio del metodo computeProductPrice
.
Un metodo puro ti chiederebbe una quantità di prodotto, una valuta, ecc. Sai che ogni volta che il metodo viene chiamato con gli stessi argomenti, produce sempre lo stesso risultato.
- Puoi persino memorizzarlo nella cache e utilizzare la versione cache.
- Puoi renderlo pigro e posticipare la chiamata quando ne hai effettivamente bisogno, sapendo che il valore non cambierà nel frattempo.
- Puoi chiamare il metodo più volte, sapendo che non avrà effetti collaterali.
- Puoi ragionare sul metodo stesso in un isolamento dal mondo, sapendo che tutto ciò di cui ha bisogno sono gli argomenti.
Un metodo non puro sarà più complesso da usare e da correggere. Dal momento che dipende dallo stato delle variabili oltre che dagli argomenti e possibilmente modificandoli, significa che potrebbe produrre risultati diversi se chiamati più volte, o non avere lo stesso comportamento quando non vengono chiamati o chiamati troppo presto o troppo tardi.
Esempio
Immagina che ci sia un metodo nel framework che analizza un numero:
decimal math.parse(string t)
Non ha trasparenza referenziale, perché dipende da:
-
La variabile di ambiente che specifica il sistema di numerazione, ovvero Base 10 o qualcos'altro.
-
La variabile all'interno della libreria math
che specifica la precisione dei numeri da analizzare. Quindi con il valore di 1
, l'analisi della stringa "12.3456"
darà 12.3
.
-
La cultura, che definisce la formattazione prevista. Ad esempio, con fr-FR
, l'analisi di "12.345"
darà 12345
, perché il carattere di separazione deve essere ,
, non .
Immagina quanto sia facile o difficile lavorare con tale metodo. Con lo stesso input, puoi avere risultati radicalmente diversi a seconda del momento in cui chiami il metodo, perché qualcosa, da qualche parte, ha cambiato la variabile d'ambiente o ha cambiato la cultura o ha impostato una precisione diversa. Il carattere non deterministico del metodo porterebbe a più bachi e più incubo di debug. Chiamare math.parse("12345")
e ottenere 5349
come risposta dal momento che alcuni codici paralleli stavano analizzando i numeri ottali non è bello.
Come risolvere questo metodo ovviamente rotto? Introducendo la trasparenza referenziale. In altre parole, eliminando lo stato globale e spostando tutto sui parametri del metodo:
decimal math.parse(string t, base=10, precision=20, culture=cultures.en_us)
Ora che il metodo è puro, sai che non importa quando chiami il metodo, produrrà sempre lo stesso risultato per gli stessi argomenti.