[swift-evolution] [Draft]: Introducing a striding(by:) method on 3.0 ranges
michel.fortin at michelf.ca
Sat Apr 9 10:53:20 CDT 2016
Le 9 avr. 2016 à 4:25, Xiaodi Wu <xiaodi.wu at gmail.com> a écrit :
> Note that it's not possible to write 9...0. Once that is clear, it's
> fairly intuitive (IMO) to look to the stride size for indicating the
> direction in which we stride, since that is the only other value there
I know it's not possible to write 9...0. But I disagree that it's intuitive that a negative step value would reverse the start and stop values. I think to be consistent it should trap, like with a step of zero, because you can't go from 0 to 9 with a negative step.
It's especially important to realize that if the step value is a variable you will not be able to know which is the start value and which is the stop criterion by quickly inspecting the code because the sign of the step is hidden away in the value of that variable.
In other words, whether the loop begins at the start or the end of the range becomes a runtime decision. There is a branch in the generator that swaps the start and end values depending on that sign. If the step value is not a literal constant, inlining might not be able to elide that branch. Add another branch to make it trap when given a step of zero. And if it traps when the range is invalid (such as in 9...0) then that's another branch to check this when you form the range. That's 3 branches needed before even starting the loop.
Perhaps I'm just complaining about loosing the good performance characteristics of a C-style for loop. In the debate about this it was stated many times that `stride` could be used and would have the same performance. Is that promise about to be broken now?
On a final note: it's common, for me at least, to enter a loop with the start position already higher than the stop criterion, essentially doing something like `stride(from: 10, to 5, by 1)` which results in the loop being skipped. Translated into this new syntax, it'd become something like `(10...5).striding(by: 1)` which of course will trap because of the invalid range, thus necessitating an extra `if` to check for this. That clutters the code and adds even more branches. Perhaps the solution to this is to not trap on ranges with a negative length, although that's probably going to cause other headaches elsewhere.
More information about the swift-evolution