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

Brent Royal-Gordon brent at architechies.com
Sun Apr 10 05:17:03 CDT 2016


> I can’t imagine any scenario in which getting the step's sign wrong wouldn’t just be a typo.

Well, it could be an error if you derive the stride by subtracting two numbers, and the second number is unexpectedly larger than the first. Of course, that makes it a *bug*, not a typo.

> Why not just assign it the correct sign during the init function?
> (0 ... 6).striding(by: 2) // [0, 2, 4, 6], end > start, so stride = by
> (6 ... 0).striding(by: 2) // [6, 4, 2, 0], start > end, so stride = -by

One reason not to do it this way is that, if we extend `striding(by:)` to other collections, they will not be as easy to walk backwards through as this. You will have to do something like `collection.reversed().striding(by:)` which will be a hassle.

And the same may apply to Range, for that matter, because…

> (OTOH, I don’t understand why 6…0 is currently a crash, rather than the, IMHO, obviously intended sequence of “6,5,4,3,2,1,0”, so maybe I’m not the best person to ask)

Well, suppose you say `6...0`. There are three ways that could be represented:

1.	Range(start: 0, end: 6)
2.	Range(start: 6, end: 0)
3.	Range(start: 0, end: 6, reversed: true)

Option 1 throws away the fact that the range was ever reversed, so it doesn't actually help with this case.

Option 2 complicates testing. Where before you might have written this:

	let inBounds = start <= x < end

Now you must write:

	let inBounds: Bool
	if start < end {
		inBounds = start <= x && x < end
	}
	else {
		inBounds = start >= x && x > end
	}

Remember, conditional branches are relatively slow, and we want to avoid them where we can. If this is, for instance, the test of a loop, the extra branch is not a good thing.

Option 3 avoids this issue, but it requires more space. It also requires branches in other places which care about order.

And both 2 and 3 complicate slicing. If you say `array[6...0] = newValues`, the operation should probably be performed such that `array[6] == newValues[0]`. That seems difficult to implement—and all too easy to forget to handle. And I can imagine that it might prevent certain optimizations if the compiler couldn't prove they were forward ranges.

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list