Per dirla in parole povere, le restrizioni significano che ci sono meno modi corretti per mettere insieme le cose, e le funzioni di prima classe facilitano il calcolo di cose come le strutture del ciclo. Esegui il ciclo da questa risposta , ad esempio:
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
iterator.remove();
}
}
Questo è l'unico modo imperativo sicuro in Java per rimuovere un elemento da una raccolta mentre si sta iterando attraverso di essa. Ci sono molti modi che sembrano molto vicini, ma sono sbagliati. Le persone che non sono a conoscenza di questo metodo a volte attraversano modi contorti per evitare il problema, ad esempio iterando attraverso una copia.
Non è terribilmente difficile renderlo generico, quindi lavorerà su più di semplici raccolte di Strings
, ma senza funzioni di prima classe, non puoi sostituire il predicato (la condizione all'interno di if
), quindi questo codice tende a essere copiato e incollato e modificato leggermente.
Combina funzioni di prima classe che ti danno l'abilità di passare il predicato come parametro, con la restrizione dell'immutabilità che lo rende molto fastidioso se non lo fai, e ti viene in mente semplici blocchi elementari come filter
, come in questo codice Scala che fa la stessa cosa:
list filter (!_.isEmpty)
Ora pensa a ciò che il sistema di tipi ti controlla, al momento della compilazione nel caso di Scala, ma questi controlli vengono eseguiti anche dai sistemi di tipo dinamico la prima volta che lo esegui:
-
list
deve essere un tipo di tipo che supporta il metodo filter
, ovvero una raccolta.
- Gli elementi di
list
devono avere un metodo isEmpty
che restituisce un valore booleano.
- L'output sarà una raccolta (potenzialmente) più piccola con lo stesso tipo di elementi.
Una volta verificate queste cose, quali altri modi sono rimasti per il programmatore di rovinare? Ho dimenticato per sbaglio il !
, che ha causato un fallimento del test case estremamente ovvio. Questo è praticamente l'unico errore disponibile, e l'ho fatto solo perché stavo traducendo direttamente dal codice testato per la condizione inversa.
Questo schema viene ripetuto più e più volte. Le funzioni di prima classe ti consentono di riordinare le cose in piccole utility riutilizzabili con una semantica precisa, le restrizioni come l'immutabilità ti danno la spinta per farlo, e digitare il controllo dei parametri di quelle utility lascia poco spazio per rovinarle.
Naturalmente, tutto dipende dal programmatore sapendo che la funzione di semplificazione come filter
esiste già, ed è in grado di trovarla, o di riconoscere il vantaggio di crearne una tu stesso. Prova a implementare questo te stesso ovunque usando solo la ricorsione a coda, e sei di nuovo nella stessa barca della complessità della versione imperativa, solo peggio. Solo perché puoi scriverlo molto semplicemente, non significa che la versione semplice sia ovvia.