Estado mutável e loops. Você quase nunca precisa deles e quase sempre obtém um código melhor sem eles.
Por exemplo, isso é obtido diretamente de um 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
Ambos estão fazendo a mesma coisa. Mas não tenho ideia do que eles estão fazendo. Felizmente, a pergunta realmente explica o que eles estão fazendo, então pude reescrevê-los da seguinte maneira:
// 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);
Não há loops nem estado mutável. Bem, ok, não explícito loops e sem contadores de loop.
O código tornou-se muito mais curto, muito mais simples, muito mais como uma descrição do que o código deveria fazer (especialmente no caso do Ruby, ele diz diretamente "agrupar as coisas por tipo") e muito menos propenso a erros. Não há perigo de executar o final da matriz, erros de barreira ou erros de um por um com os índices de loop e condições de finalização, porque não há índices de loop e condições de finalização.