Stato e loop mutabili. Non ne hai quasi mai bisogno e quasi sempre ottieni un codice migliore senza di loro.
Ad esempio, questo è preso direttamente da un thread StackOverflow:
// ECMAScript
var thing, things_by_type = {};
for (var i = 0; i < things.length; i++) {
thing = things[i];
if(things_by_type[thing.type]) {
things_by_type[thing.type].push(thing);
} else {
things_by_type[thing.type] = [thing];
}
}
# Ruby
things_by_type = {}
things.each do |thing|
(things_by_type[thing.type] ||= []) << thing
end
Entrambi stanno facendo la stessa cosa. Ma non ho idea di ciò che fanno . Fortunatamente, la domanda spiega in realtà cosa stanno facendo, quindi sono stato in grado di riscriverli come segue:
// ECMAScript
things.reduce(function (acc, thing) {
(acc[thing.type] || (acc[thing.type] = [])).push(thing);
return acc;
}, {});
# Ruby
things.group_by(&:type)
// Scala
things groupBy(_.type)
// C#
from thing in things group thing by thing.Type // or
things.GroupBy(thing => thing.Type);
Non ci sono loop e nessuno stato mutabile. Bene, okay, nessun ciclo esplicito e nessun contatore di loop.
Il codice è diventato molto più breve, molto più semplice, molto più simile a una descrizione di ciò che il codice dovrebbe fare (specialmente nel caso Ruby dice direttamente "raggruppa le cose per tipo") e molto meno errore -prone. Non c'è pericolo di scappare dalla fine dell'array, errori di fencepost o errori off-by-one con gli indici di loop e le condizioni di terminazione, perché non ci sono indici di loop e condizioni di terminazione.