[swift-evolution] [Review] SE-0007 Remove C-style for-loops with conditions and incrementers
Michel Fortin
michel.fortin at michelf.ca
Thu Dec 10 11:16:18 CST 2015
Review for SE-0007 Remove C-style for-loops with conditions and incrementers
https://github.com/apple/swift-evolution/blob/6e121f714bcbade5860aa74bdc3523a14a9cf0b8/proposals/0007-remove-c-style-for-loops.md
# What is your evaluation of the proposal?
Even though I do not dislike the idea, I think the disappearance of the C-style for loop should at least be accompanied with decent migration measures. Nothing very convincing has been proposed in that regard. So I disagree with the proposal as it stands today.
# Is the problem being addressed significant enough to warrant a change to Swift?
One of the argument is that this loop is rarely used. I tend to disagree: this loop exists in many other mainstream languages: code using it can be found everywhere. What would be a simple transliteration of an algorithm to port it to Swift can easily become a mess if you have to refactor the loop at the same time. This makes the delicate process more painful and error-prone.
Even if in theory it would make sense to refactor all C-style for loops with for-in or while loops, this is not always easy, or convenient, and most importantly it does not always result in more readable code.
I do agree the syntax is not great. It's not very intuitive and the readability is poor. It should ideally be replaced by something better. But using for-in and while, as they exist currently, does not cut it.
# Does this proposal fit well with the feel and direction of Swift?
I would really like if the C-style for loop could be replaced with something more intuitive. And if it did, I would expect Swift to provide a migration path to remove C-style for loops and replace them by something equivalent. What kind of code is a migration tool going to generate for this proposal? This isn't addressed very clearly, and I suspect the results won't be so pretty.
You can't replace C-style for loops with for-in in the general case. Using a "while" loop will always be possible, but also much more verbose. For instance, take this loop iterating downward over i and j in lockstep:
for var i = 10, j = 20; i > 0 && j > 0; i -= 1, j -= 2 {
... loop body ...
}
The only fully-compatible while loop that makes sense is this one:
do {
var i = 10
var j = 20
var first = true
while true {
if first { first = false }
else { i -= 1; j -= 2 }
guard i > 0 && j > 0 else { break }
... loop body ...
}
}
If the loop body contains a continue, it works. If the loop body mutates one of the loop variables, it works. If the loop throws, it works. If the outer scope has a variable with the same name, it works! There is no code duplication. But oh boy, the boilerplate!
Not all loops contain a continue, or need to mutate its loop variable, or throw. There is an abundance of simpler patterns that can apply to these particular cases. But any of these patterns based on a while loop are more fragile than a C-style for loop. Introduce one continue, or one throw, and the loop needs some refactoring to correctly maintain the loop state. The only robust loop pattern is the for-in loop, but its applicability is limited, especially when applied by an automated tool.
Therefore, to keep the same semantics, any migration tool should use as a replacement either a for-in (for simple forward iteration, the most common case), or the above while loop. Needless to say, nobody is going to be happy seeing a C-style for loop replaced by a while loop like above. There needs to be a better way to express that loop.
Don't forget that migration in this case is not only a Swift 2 to Swift 3 thing, it's also a foreign language to Swift 3 thing.
# If you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
When I was learning programming, I used Pascal a lot. There was no equivalent to the C-style for loop. (There was no break, continue, or return either.) There was a for loop to iterate over a range of numbers, up or down, but sometime that for loop was not enough. So I learned to use variables to control the state of a while loop and express the condition for exiting the loop in term of those variables. The logic for that had to be scattered all across the loop body. This is what the equivalent while loop reminds me of.
The for loop from C is a power tool: it lets you express the loop control variables, the exit condition, and the prepare-the-next-iteration statement all together in one place, cleaning the loop body from the bookkeeping work, and properly handling special cases such as "continue". It's a useful middle ground between the strongly abstracted for-in loop and the almost unstructured "while" loop.
# How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I read most messages on the mailing list, made a few proposals, found out a a couple of alternatives and figured out their limitations. I also remembered an experience with someone I worked with, who was better at math than at coding, and for whom a C-style for loop with all the inner working exposed would feel much more reassuring than a clever abstracted sequence type in a for-in loop.
--
Michel Fortin
michel.fortin at michelf.ca
https://michelf.ca
More information about the swift-evolution
mailing list