Stato mutevole e loop. Non hai quasi mai bisogno di loro e quasi sempre ottieni un codice migliore senza di loro.
Ad esempio, questo viene 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
Stanno entrambi facendo la stessa cosa. Ma non ho idea di cosa stiano facendo. Fortunatamente, la domanda in realtà spiega 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 anelli e nessuno stato mutabile. Bene, ok, nessun loop 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 di Ruby dice praticamente direttamente "raggruppa le cose per tipo") e molto meno soggetto a errori. 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.