[swift-evolution] [Draft]: Introducing a striding(by:) method on 3.0 ranges

Xiaodi Wu xiaodi.wu at gmail.com
Sat Apr 9 12:23:35 CDT 2016

The sign of the stride size is already (in the current version of Swift)
evaluated in the stride generator/iterator; as written, it is evaluated
every time next() is called, but of course that is optimized away when
possible. What we are proposing adds no additional logic to the loop. I
can't see a reason why inserting a line to trap on a negative stride size
would show any measurable improvement in performance compared to inserting
a line to use upperBound for start and lowerBound for end instead of vice
versa when initializing an instance of StrideTo/StrideThrough. This would
not be a branch in StrideToIterator.next(), nor even in
StrideToIterator.init(), but rather in StrideTo.init() or even
striding(by:). Rest assured that degrading performance for the most common
use case would be unacceptable (at least to me).

It is already the case that your code needs to account for the sign of the
stride size. Currently, not doing so runs the risk of unintentionally
creating an empty sequence. In our proposal, the result of using a stride
size of unintended sign would differ but the fact that you need to account
for it is unchanged. We are not proposing trapping on negative stride sizes
nor allowing ranges such as 9...0.
On Sat, Apr 9, 2016 at 4:53 PM Michel Fortin <michel.fortin at michelf.ca>

> 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
> > is.
> 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.
> --
> Michel Fortin
> https://michelf.ca
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160409/f9e8eeac/attachment.html>

More information about the swift-evolution mailing list