First, a nitpick: Kotlin can’t keep the old-style for ()
loop, because it never had it in the first place! So this question is really a proposal to add it to the language. But is there sufficient reason to do so? Not that I can see.
When it was introduced, the old-style for ()
loop had one major advantage: it was comprehensive. Its flexibility allowed you to write any type of loop: loops that iterated a fixed number of times; loops that iterated until a condition was met; loops that increment a counter, or decrement it, or follow pointer chains, or anything, or nothing; you could even control multiple loop variables with it. So C didn’t need separate language constructs for all these different types of loop: the single for ()
does them all.
(However, note that C also has while ()
and do…while ()
loops, even though the for ()
loop can cover those cases too. So the author clearly felt there was a need for some special cases, even then…)
However, the price for that flexibility is complexity, verbosity, and difficulty of reading and maintaining. For a common fixed-count iteration, you need to specify the loop variable three times, which discourages long and meaningful names; the order of clauses doesn’t match the usual thought process (putting the increment after the upper limit); it’s very easy to get the termination condition wrong (<=
vs <
); and other mistakes are also surprisingly easy to make and hard to spot (e.g. testing or updating the wrong variable), especially when counting down instead of up.
C’s for
loop also works well with a couple of its other ultra-concise features: implied tests for zero/null, and assignments within expressions — features which are neat but error-prone, and don’t scale well to larger programs. For safety, languages such as Kotlin deliberately omit those features, reducing the benefit of the old-style for
.
And in practice, in Kotlin the majority of loops iterate through the elements of some structure (list, or array, or similar); they don’t need all that complexity. (When Java introduced its ‘enhanced’ for-each loop, I found that nearly all of our loops could be replaced by it — and were simpler, clearer, and safer for doing so. Even fixed-size iterations were often a disguised way of iterating through some structure. Very few old-style for ()
loops remained — and they tended to be the awkward ones that were probably ripe for rewriting anyway.)
So in C (and Java ≤4), most loops are more complicated and awkward than they need to be, simply to cope with the rare cases where that complexity is needed.
With the benefit of hindsight, Kotlin makes the common case very simple, short, easy to read, and almost impossible to get wrong.
It also covers many of the remaining cases with extension methods (e.g. Reader.useLines()
avoids the need to read a line at a time until it’s null (and also takes care of closing the reader).
In my experience, that covers the vast majority of loops. And for the few which remain, you can always use while ()
or do…while ()
, which can do anything that the old-style for ()
could. They can’t do it all in one line, but that’s arguably a good thing for readability! The only significant disadvantage is that you can’t restrict the loop variable(s) to the loop’s scope, but that’s not a major issue — and in some cases you want to check it after the loop has finished anyway.
So why would Kotlin benefit from adding the old-style for
loop? Every case that would use it is already catered for — mostly in ways that are far better.
Even the supposed benefit of familiarity is reducing year by year, as C and the languages it inspired fade, or are updated to include modern-style loops too. (I’m of a generation that grew up with C — it was my main professional language for several years — and then I used Java for several more years before it gained the enhanced for-each loop, so I have a lot of experience with the old-style for
. But I found the new-style for-each loop trivially easy to learn, and very natural to use.
So I see nothing that comes anywhere near to outweighing the default -100 points for a new language feature. Kotlin is a great language, not just for what it includes, but for what it omits. Any new feature must ‘pull its weight’, bringing sufficient benefits to justify the extra complexity of implementing it (and supporting it for ever more), of learning how to use it, of understanding it in other people’s code, of avoiding new types of bug, and even of answering questions about it on sites such as this one when people have trouble learning or using it…