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

Xiaodi Wu xiaodi.wu at gmail.com
Sun Apr 10 15:15:17 CDT 2016

On Sun, Apr 10, 2016 at 3:58 PM, Haravikk <swift-evolution at haravikk.me> wrote:
> On 10 Apr 2016, at 14:25, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> What types do you have in mind that would only support positive distances?
> All numeric types (yes, even UInt, etc.) have signed distances, which
> reflects the basic mathematical abstraction of a number line.
> Say you wanted to stride through a singly-linked list, it would actually be
> beneficial to support only forward strides, the same is true of sequences,
> as you either may not know what the endpoint is, or would have to step
> through the whole sequence to find it (plus buffer every value in order to
> do-so safely).
> A consistent behavior with signed distances is so important that we are
> currently struggling with an interesting issue with floating point types,
> which is that due to rounding error 10.0 + a - a != 10.0 for some values of
> a.
> While that’s interesting I’m not sure why the sign is important; to me a
> stride is a width so it being negative makes no sense. For example, say I
> laid an array of Ints, organised into groups of five (and also that I’m
> lunatic who won’t use a tuple for this), the stride of this array is 5
> whether I’m stepping through it forwards or backwards. Imagine I defined
> this like so (more realistically it’d be a struct or a class):
> typealias StridedIntegerArray:(stride:Int, array:[Int])
> If the stride is set to 5, it’s always 5, the only thing that changes is
> whether I want to stride from the start or end of the array, plus I could
> things like:
> myStridedIntegerArray.prefix(from: 2).striding(forwardBy:
> myStridedIntegerArray.stride) // Returns element at index 2, 7, 12, etc.

When you have a sequence returning elements at index 12, 7, 2, etc.,
wouldn't you call the stride size -5? I would, because 12 + (-5) = 7.

> It just occurred to me that perhaps you intended this method only for ranges
> specifically and that perhaps I’m confusing things, but it seems to me like
> it should be a method for all sequences (with reverse stride available on
> collections with a reverse index type) returning a generator that only
> returns (or computes) every Nth element, for generic sequences/collections
> this would take the start or end index and use advanced(by:), though again,
> I kind of feel like that should be two separate methods as well, but that’s
> for another issue I think.

I don't think it should be for ranges only, but ranges are the extent
of this proposal.

That said, my own opinion is that striding should not be available on
sequences but on collections only. In their most commonly used form,
integer strides take a start and end, and there is a finite number of
things to stride over; thus, in my reasoning, strides can be extended
to cover anything else that has a known start and end and has a finite
number of things, which is guaranteed by conformance to Collection but
not to Sequence. (At the moment, StrideTo/Through conforms to Sequence
and not to Collection, but that is considered something to be fixed
and we will see if we can address that as part of this set of stride

As I see it, we agree on the problem: the current algorithm cannot
accommodate singly linked lists and sequences because those things do
not have a known endpoint if you begin an attempt to stride. However,
my conclusion is the opposite of yours: namely, that they should not
have stride. Maybe they should have something similar, but it
shouldn't be stride.

> On Sun, Apr 10, 2016 at 12:53 PM Haravikk via swift-evolution
> <swift-evolution at swift.org> wrote:
>> On 10 Apr 2016, at 11:17, Brent Royal-Gordon <brent at architechies.com>
>> wrote:
>> 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.
>> Any thoughts on the alternative I mentioned a little earlier to define
>> overloads instead of positive/negative? i.e- you would have two methods,
>> .striding(forwardBy:) and .striding(backwardBy:). In addition to eliminating
>> the use of a negative stride to indicate direction, this has the advantage
>> that .striding(backwardBy:) can be defined only for types with a
>> ReverseIndex or only for collections (as you can stride through a sequence,
>> but only by going forward).
>> This should also make documentation a bit clearer, otherwise you’ve got
>> the caveat that to go backwards requires a negative value, but only if the
>> type supports that, which a developer would then need to check. Instead it
>> either has the backwardBy variant or not.
>> I know that advance(by:) supports negative values, but this is actually
>> something I wouldn’t mind seeing changed as well, as it has the same issues
>> (passing a negative value in looks fine until you realise the type is a
>> ForwardIndex only). It would also allow us to define Distance types that
>> don’t support a direction, since this would be given by the choice of method
>> called instead.
>> Of course I’d still like to be able to define 6 … 0 or whatever, but this
>> would at least eliminate what I dislike about using negatives for direction.
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list