Feature proposal: Range operator with step

Question: by what unit should

       for d in d0...d2 {}

be iterating? Or should it be disallowed without a .striding(by: )?

If the latter, NSDate might fall into the same bucket as floating types.

Floating-point seconds (as NSTimeIntervals) are the natural Strideable.Stride, but it's not particularly clear to me that you want 1 second to be a default stride. It's the default you would guess, but it's not actually a particularly useful default.

···

--
Brent Royal-Gordon
Architechies

Ah, I think the conceptual muddle arises in the plan then. Specifically,
I'd argue that not all Ranges with Strideable bounds should conform to
Collection.

Conceptually, whether a type can be advanced by some distance (guaranteed
by Strideable) is orthogonal to whether a type has an obviously correct
increment when calling next() on its iterator. Thus, although *strides*
with Strideable bounds should obviously conform to Collection, Ranges that
conform to Collection should be constrained to types which imply that the
Range represents a countable set (as the mathematicians say) of numbers.

This distinction may come in handy for implementing strides that don't
accumulate error. Striding through a Range that represents a countable set
of elements shouldn't accumulate error and we can use what we already
have--i.e. increment the current value every iteration without inspecting
the value of the starting bound. Striding through a Range that represents
an uncountable set of elements definitely requires reckoning from the
starting bound every iteration.

···

On Fri, Mar 25, 2016 at 11:25 AM Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Thu Mar 24 2016, Xiaodi Wu <swift-evolution@swift.org> wrote:

> On Thu, Mar 24, 2016 at 4:18 PM, Dave Abrahams via swift-evolution > > <swift-evolution@swift.org> wrote:
>>
>> on Wed Mar 23 2016, Xiaodi Wu <swift-evolution@swift.org> wrote:
>>
>>> So, in other words, you'd be satisfied with the following addition to
>>> the standard library?
>
>>>
>>> ```
>>> extension Range where Element: Strideable {
>>> func by(step: Element.Stride) -> StrideTo<Element> {
>>> return startIndex.stride(to: endIndex, by: step)
>>> }
>>> }
>>>
>>> /*
>>> example of usage:
>>>
>>> for i in (1..<10).by(2) {
>>> print(i)
>>> }
>>> */
>>> ```
>>
>>
>> My current thinking is that:
>>
>> * `for x in 0.0..<3.0 {}` should probably be an error, because 1.0 is
>> not the obviously-right stride to use for non-integral numbers. That
>> would imply that floating types should not conform to Strideable,
>> which raises the question of whether Strideable should be folded into
>> the Integer protocol.
>
> Well, maybe I'm missing something, but `for x in 0.0..<3.0 { }`
> doesn't work as it is, and it doesn't seem to have anything to do with
> Strideable. Rather, HalfOpenInterval<Double> doesn't conform to
> SequenceType.

True, but the plan is that:

* Interval is going away
* Range will only require that its Bound be Comparable
* Ranges with Strideable bounds will conform to Collection

(see the swift-3-indexing-model branch on GitHub)

> I agree that `for x in 0.0..<3.0 { }` should continue not working, but
> maybe let's keep floating point types conforming to Strideable :)

Those two things are not compatible with the plan we're going to
propose, as described above.

>>
>> * `for x in (0.0..<20.0).striding(by: 1.3) {}` should work without
>> accumulating error
>>
>
> +1.
>
>> * `for x in 0..<3 {}` should work (obviously; that's the status quo)
>>
>> * `for x in (0..<20).striding(by: 2)` should work
>>
>> I think this might also handle the concerns that
>>
https://github.com/apple/swift-evolution/blob/master/proposals/0051-stride-semantics.md
>> was trying to address.
>>
>> If I thought extreme concision was important for this application, I'd
be
>> proposing something like
>>
>> for x in 0.0..<20.0//1.3 {}
>>
>> but personally, I don't, which is why I propose `.striding(by: x)`
>> rather than simply `.by(x)`, the latter being more open to
>> misinterpretation.
>
> Yeah, `.striding(by: x)` is pretty good.
>
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

for i in p1..<p2 by x

as syntactic sugar for and internally mapped to

for i in (p1..<p2).striding(by: x)

Best of both worlds?

Look. It is very, very unlikely that you will get people to add syntactic sugar *just* for striding and *just* for the for loop. If this:

  for i in (1..<10).striding(by: 2) { … }

Is so ugly that we need special syntactic sugar for it, then so is this:

  (1..<10).striding(by: 2).map { … }

That means we would need an expression along the lines of:

  1..<10 by 2

Which could be used anywhere. Unfortunately, Swift does not allow word characters in identifiers, so `by` as an operator is a non-starter. I can't think of a non-letter operator for `by` that would make sense, so we're probably not going to go that route, either (but if you have a suggestion—preferably one backed by existing notation from, say, math—by all means suggest it).

I don't think you're going to make anything happen here.

···

--
Brent Royal-Gordon
Architechies

What about "strideby"

Brandon

···

On Apr 14, 2016, at 8:57 PM, Hans Huck via swift-evolution <swift-evolution@swift.org> wrote:

Erica Sadun via swift-evolution <swift-evolution@...> writes:

On Apr 14, 2016, at 1:42 PM, Hans Huck via swift-evolution > <swift-evolution <at> swift.org> wrote:
Please elaborate. How could

for i in (1...10).by(3)

possibly be misinterpreted?

(1..<11), (4..<14), (7..<17)...

Or (3..<30)? :)

With that reasoning, "for in" would have to be changed to "for each" to
avoid possible misinterpretation; after all, "i" could be a range and "for i
in" could test if it's a subrange of (1...10).

Basically, there is no such thing as "unmistakable", not least because the
very same keywords and symbols are being used for different purposes in
different languages. There are only degrees of clarity.

Anyway, why not just make it .step() then, like in Ruby?

Instead of a "by" keyword, I'd be happy with syntactic sugar in the form of

for i in p1..<p2 step x

too, btw.

-- Hans

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

“|” often means “with” in math, which is only one word off from “with step”.
func | <T: Strideable where T.Stride : IntegerType> (range: Range<T>, stride: T.Stride) -> IntegerStrideTo<T> {
    return IntegerStrideTo(_start: range.startIndex, end: range.endIndex, stride: stride)
}
var arr = [Int]()
for i in (0 ..< 10) | 2 {
    arr.append(i)
}
arr //[0,2,4,6,8]

I couldn’t figure out how to do it without the parens… everything I could think to try is determined to parse as `(0) ..< (10 | 2)`, so `arr` ends up equalling [0,1,2,3,4,5,6,7,8,9]. If operator precedence and associativity were per-function rather than per-op, it could be made to work without the ().

- Dave Sweeris

···

On Apr 14, 2016, at 8:27 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

That means we would need an expression along the lines of:

  1..<10 by 2

Which could be used anywhere. Unfortunately, Swift does not allow word characters in identifiers, so `by` as an operator is a non-starter. I can't think of a non-letter operator for `by` that would make sense, so we're probably not going to go that route, either (but if you have a suggestion—preferably one backed by existing notation from, say, math—by all means suggest it).

Brent Royal-Gordon via swift-evolution <swift-evolution@...> writes:

> for i in p1..<p2 by x
>
> as syntactic sugar for and internally mapped to
>
> for i in (p1..<p2).striding(by: x)
>
> Best of both worlds?

Look. It is very, very unlikely that you will get people to add syntactic
sugar *just* for striding and *just* for the for loop. If this:

  for i in (1..<10).striding(by: 2) { … }

Is so ugly that we need special syntactic sugar for it, then so is this:

  (1..<10).striding(by: 2).map { … }

It's unnecessarily unwieldy, and I'd prefer `.by(x)`, `.step(x)`, or even
`.stride(x)` over `.striding(by: x)` any day. I understand potential
reservations towards "by", even though I don't share them, but these cannot
possibly apply to "step" or "stride".

That means we would need an expression along the lines of:

  1..<10 by 2

Which could be used anywhere.

That's where I disagree. You see, what I'm trying to achieve here is not to
fight tooth and claw for an ever shorter step syntax in collections.

I just want to *get rid of an anomaly*, which imo justifies a new keyword
for a (heavily utilized) special case.

So far, you can fully use all core control structures in Swift without
resorting to methods/protocols, let alone noisy ones. While, While-Repeat,
If-Else, Switch, and (plain) For-In all work in a straight forward,
imperative, expected way, and that's highly desirable, because it's
intuitive and comes free of cognitive load.

But by removing (which btw I fully support) the C-style For-loop from the
language, suddenly one of the simplest and most primal tasks stands out
unpleasantly:

Counting from x to y with a step size of z -- which is the very application
the For-loop originally was created for.

Would you like to be forced to work with a While-loop like the one below?

while i.loop(initialize: 1, conditionlessorequal: 10, increaseby: 3)

Yeah, me neither ;)

Again: I'm not aiming at collection syntax in general; it just gets in the
line of fire, because the only remaining For-loop in Swift currently doesn't
know how to step through a sequence of numbers without making a fuss.

-- Hans

As for 'step' word: It seems like for now IMO this is the best suggestion : very explicit, anyone knows what "step" means especially in context of loop, clear that "step" belongs to for-in construction(not to range itself).

for i in 0..<10 step 2 {
}

for i in 0..<10 step -2 {
}

for i in 0.1..<10.5 step 0.5 {
}

all are mapped to needed ranges/intervals under the hood
Do you want some custom Range-specific methods to provide steps for loop - no problems, use what you need. But don't force any of us to use (0..<10).striding(by:2) for myriads of simple loops in our code.

I want to see such constructions in our Swift. Who is with me ? :)

···

On 15.04.2016 3:57, Hans Huck via swift-evolution wrote:
> Anyway, why not just make it .step() then, like in Ruby?
>
> Instead of a "by" keyword, I'd be happy with syntactic sugar in the form of
>
> for i in p1..<p2 step x

Huge +1 from me, but a character can't be valid for both function/variable names and operators because it'd break something in the compiler. Or at least I think that’s what I remember reading here.

That doesn’t strictly rule out custom keywords, but those are probably part of the AFAIK-still-out-of-scope macro discussion.

- Dave Sweeris

···

On Mar 24, 2016, at 9:24 AM, David Knothe via swift-evolution <swift-evolution@swift.org> wrote:

Well I would love to be able to create and use my own keywords / alphanumeric operators.
Depending on the type of code you are writing, these may be more or less helpful. The same is true for the 'step' keyword - maybe most people won't ever use it - but I think there should certainly be a possiblity, be it a concrete keyword built into the language or the possibility to create my own ones.

Ah, I think the conceptual muddle arises in the plan
then. Specifically, I'd argue that not all Ranges with Strideable
bounds should conform to Collection.

Conceptually, whether a type can be advanced by some distance
(guaranteed by Strideable) is orthogonal to whether a type has an
obviously correct increment when calling next() on its iterator. Thus,
although *strides* with Strideable bounds should obviously conform to
Collection, Ranges that conform to Collection should be constrained to
types which imply that the Range represents a countable set (as the
mathematicians say) of numbers.

I think any countable set should be OK, regardless of whether the
elements are numbers. Ranges of UnsafePointers, for example, are
countable.

This distinction may come in handy for implementing strides that don't
accumulate error. Striding through a Range that represents a countable
set of elements shouldn't accumulate error and we can use what we
already have--i.e. increment the current value every iteration without
inspecting the value of the starting bound. Striding through a Range
that represents an uncountable set of elements definitely requires
reckoning from the starting bound every iteration.

So, what does this Countable protocol look like? It seems like it would
bring back the Index protocols that are otherwise obviated by this
plan... not a jolly prospect.

···

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

On Fri, Mar 25, 2016 at 11:25 AM Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:

on Thu Mar 24 2016, Xiaodi Wu <swift-evolution@swift.org> wrote:

> On Thu, Mar 24, 2016 at 4:18 PM, Dave Abrahams via swift-evolution >> > <swift-evolution@swift.org> wrote:
>>
>> on Wed Mar 23 2016, Xiaodi Wu <swift-evolution@swift.org> wrote:
>>
>>> So, in other words, you'd be satisfied with the following addition to
>>> the standard library?
>
>>>
>>> ```
>>> extension Range where Element: Strideable {
>>> func by(step: Element.Stride) -> StrideTo<Element> {
>>> return startIndex.stride(to: endIndex, by: step)
>>> }
>>> }
>>>
>>> /*
>>> example of usage:
>>>
>>> for i in (1..<10).by(2) {
>>> print(i)
>>> }
>>> */
>>> ```
>>
>>
>> My current thinking is that:
>>
>> * `for x in 0.0..<3.0 {}` should probably be an error, because 1.0 is
>> not the obviously-right stride to use for non-integral numbers. That
>> would imply that floating types should not conform to Strideable,
>> which raises the question of whether Strideable should be folded into
>> the Integer protocol.
>
> Well, maybe I'm missing something, but `for x in 0.0..<3.0 { }`
> doesn't work as it is, and it doesn't seem to have anything to do with
> Strideable. Rather, HalfOpenInterval<Double> doesn't conform to
> SequenceType.

True, but the plan is that:

* Interval is going away
* Range will only require that its Bound be Comparable
* Ranges with Strideable bounds will conform to Collection

(see the swift-3-indexing-model branch on GitHub)

> I agree that `for x in 0.0..<3.0 { }` should continue not working, but
> maybe let's keep floating point types conforming to Strideable :)

Those two things are not compatible with the plan we're going to
propose, as described above.

>>
>> * `for x in (0.0..<20.0).striding(by: 1.3) {}` should work without
>> accumulating error
>>
>
> +1.
>
>> * `for x in 0..<3 {}` should work (obviously; that's the status quo)
>>
>> * `for x in (0..<20).striding(by: 2)` should work
>>
>> I think this might also handle the concerns that
>>
https://github.com/apple/swift-evolution/blob/master/proposals/0051-stride-semantics.md
>> was trying to address.
>>
>> If I thought extreme concision was important for this application, I'd
be
>> proposing something like
>>
>> for x in 0.0..<20.0//1.3 {}
>>
>> but personally, I don't, which is why I propose `.striding(by: x)`
>> rather than simply `.by(x)`, the latter being more open to
>> misinterpretation.
>
> Yeah, `.striding(by: x)` is pretty good.
>
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

Ah, I think the conceptual muddle arises in the plan
then. Specifically, I'd argue that not all Ranges with Strideable
bounds should conform to Collection.

Conceptually, whether a type can be advanced by some distance
(guaranteed by Strideable) is orthogonal to whether a type has an
obviously correct increment when calling next() on its iterator. Thus,
although *strides* with Strideable bounds should obviously conform to
Collection, Ranges that conform to Collection should be constrained to
types which imply that the Range represents a countable set (as the
mathematicians say) of numbers.

I think any countable set should be OK, regardless of whether the
elements are numbers. Ranges of UnsafePointers, for example, are
countable.

This distinction may come in handy for implementing strides that don't
accumulate error. Striding through a Range that represents a countable
set of elements shouldn't accumulate error and we can use what we
already have--i.e. increment the current value every iteration without
inspecting the value of the starting bound. Striding through a Range
that represents an uncountable set of elements definitely requires
reckoning from the starting bound every iteration.

So, what does this Countable protocol look like? It seems like it would
bring back the Index protocols that are otherwise obviated by this
plan... not a jolly prospect.

···

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

--
Dave

I'd reply inline but I'm working around some technical limitations on the go here. Agreed that anything countable should be good for a Range that conforms to Collection. Well, anything finite, maybe. See below about countably infinite ranges.Re hypothetical Countable protocol:I'm not advocating for another protocol for the numeric type. I'll take your word for it that they aren't jolly, though I don't know why.The issue as I see it is this: currently, Range is documented as a collection of *discrete* index values. If Intervals are going away, does a Range<Float> model a countable set of Floats with unit stride, a finite set of Floats in the technical sense that there exists only a finite set of representable numbers, or an uncountable set?The former two preserves the current definition of Range as a collection of discrete values but may be astonishing to users. But, if we agree that the last scenario is most intuitive, how then can we make the distinction between a "Range" that represents an uncountable set of things with an upper and lower bound and one that represents a countable set of things?Thinking more on this, expanding Range to floating point types opens you up to another inconsistency. Can the bounds be -inf and inf? I don't see why that should be a problem for an Interval, but now we're in for some trouble if you want it for a Range that can be strided through. How about 0.0 and inf? That makes sense to allow. But why should the ranges I'm allowed to specify be constrained by what makes sense to stride?So the more I think about it, the more I'm convinced that the logic for what Range-Interval hybrids can be strided through can't neatly accommodate floating point types. If you merge Range and Interval, I still want to be able to specify `-Double.infinity..<Double.infinity`. But if I can do that, then Range<Double> shouldn't even have `striding(by:)`.

···

From: Dave Abrahams via swift-evolution <swift-evolution@swift.org>
Sent: Friday, March 25, 2016 8:11 PM
Subject: Re: [swift-evolution] Feature proposal: Range operator with step
To: <swift-evolution@swift.org>

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

Ah, I think the conceptual muddle arises in the plan
then. Specifically, I'd argue that not all Ranges with Strideable
bounds should conform to Collection.

Conceptually, whether a type can be advanced by some distance
(guaranteed by Strideable) is orthogonal to whether a type has an
obviously correct increment when calling next() on its iterator. Thus,
although *strides* with Strideable bounds should obviously conform to
Collection, Ranges that conform to Collection should be constrained to
types which imply that the Range represents a countable set (as the
mathematicians say) of numbers.

I think any countable set should be OK, regardless of whether the
elements are numbers. Ranges of UnsafePointers, for example, are
countable.

This distinction may come in handy for implementing strides that don't
accumulate error. Striding through a Range that represents a countable
set of elements shouldn't accumulate error and we can use what we
already have--i.e. increment the current value every iteration without
inspecting the value of the starting bound. Striding through a Range
that represents an uncountable set of elements definitely requires
reckoning from the starting bound every iteration.

So, what does this Countable protocol look like? It seems like it would
bring back the Index protocols that are otherwise obviated by this
plan... not a jolly prospect.

--
Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Question: by what unit should

       for d in d0...d2 {}

be iterating? Or should it be disallowed without a .striding(by: )?

If the latter, NSDate might fall into the same bucket as floating types.

Floating-point seconds (as NSTimeIntervals) are the natural
Strideable.Stride,

In what sense, given what you say below? Isn't this assertion of yours
just an artifact of how NSTimeInterval is defined, rather than anything
intrinsic to dates?

···

on Fri Mar 25 2016, Brent Royal-Gordon <brent-AT-architechies.com> wrote:

but it's not particularly clear to me that you want 1 second to be a
default stride. It's the default you would guess, but it's not
actually a particularly useful default.

--
Dave

Any fixed-time-period stride with dates is fraught with peril. Not every day is 24 hours, not every minute is 60 seconds, etc. Working with dates requires enough special domain knowledge that I think it'd be harmful to try to genericize numeric concepts over it.

-Joe

···

On Mar 25, 2016, at 4:09 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Question: by what unit should

      for d in d0...d2 {}

be iterating? Or should it be disallowed without a .striding(by: )?

If the latter, NSDate might fall into the same bucket as floating types.

Floating-point seconds (as NSTimeIntervals) are the natural Strideable.Stride, but it's not particularly clear to me that you want 1 second to be a default stride. It's the default you would guess, but it's not actually a particularly useful default.

+1

-Thorsten

···

Am 25.03.2016 um 17:24 schrieb Jordan Rose via swift-evolution <swift-evolution@swift.org>:

On Mar 25, 2016, at 9:19 , Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu Mar 24 2016, Brent Royal-Gordon <swift-evolution@swift.org> wrote:

That
would imply that floating types should not conform to Strideable,
which raises the question of whether Strideable should be folded into
the Integer protocol.

Personally, I get a lot of mileage out of conforming NSDate to
Strideable.

I just recalled that Unsafe[Mutable]Pointers are also Strideable. So
Strideable stays.

Question: by what unit should

      for d in d0...d2 {}

be iterating? Or should it be disallowed without a .striding(by: )?

If the latter, NSDate might fall into the same bucket as floating types.

Strong vote to require a unit here, especially given that .minutes, .hours, .days, .months, and .years are all non-uniform intervals that are nonetheless useful to stride by!

Jordan
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Good points!

-Thorsten

···

Am 25.03.2016 um 19:29 schrieb Xiaodi Wu via swift-evolution <swift-evolution@swift.org>:

Ah, I think the conceptual muddle arises in the plan then. Specifically, I'd argue that not all Ranges with Strideable bounds should conform to Collection.

Conceptually, whether a type can be advanced by some distance (guaranteed by Strideable) is orthogonal to whether a type has an obviously correct increment when calling next() on its iterator. Thus, although *strides* with Strideable bounds should obviously conform to Collection, Ranges that conform to Collection should be constrained to types which imply that the Range represents a countable set (as the mathematicians say) of numbers.

This distinction may come in handy for implementing strides that don't accumulate error. Striding through a Range that represents a countable set of elements shouldn't accumulate error and we can use what we already have--i.e. increment the current value every iteration without inspecting the value of the starting bound. Striding through a Range that represents an uncountable set of elements definitely requires reckoning from the starting bound every iteration.

On Fri, Mar 25, 2016 at 11:25 AM Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu Mar 24 2016, Xiaodi Wu <swift-evolution@swift.org> wrote:

> On Thu, Mar 24, 2016 at 4:18 PM, Dave Abrahams via swift-evolution >> > <swift-evolution@swift.org> wrote:
>>
>> on Wed Mar 23 2016, Xiaodi Wu <swift-evolution@swift.org> wrote:
>>
>>> So, in other words, you'd be satisfied with the following addition to
>>> the standard library?
>
>>>
>>> ```
>>> extension Range where Element: Strideable {
>>> func by(step: Element.Stride) -> StrideTo<Element> {
>>> return startIndex.stride(to: endIndex, by: step)
>>> }
>>> }
>>>
>>> /*
>>> example of usage:
>>>
>>> for i in (1..<10).by(2) {
>>> print(i)
>>> }
>>> */
>>> ```
>>
>>
>> My current thinking is that:
>>
>> * `for x in 0.0..<3.0 {}` should probably be an error, because 1.0 is
>> not the obviously-right stride to use for non-integral numbers. That
>> would imply that floating types should not conform to Strideable,
>> which raises the question of whether Strideable should be folded into
>> the Integer protocol.
>
> Well, maybe I'm missing something, but `for x in 0.0..<3.0 { }`
> doesn't work as it is, and it doesn't seem to have anything to do with
> Strideable. Rather, HalfOpenInterval<Double> doesn't conform to
> SequenceType.

True, but the plan is that:

* Interval is going away
* Range will only require that its Bound be Comparable
* Ranges with Strideable bounds will conform to Collection

(see the swift-3-indexing-model branch on GitHub)

> I agree that `for x in 0.0..<3.0 { }` should continue not working, but
> maybe let's keep floating point types conforming to Strideable :)

Those two things are not compatible with the plan we're going to
propose, as described above.

>>
>> * `for x in (0.0..<20.0).striding(by: 1.3) {}` should work without
>> accumulating error
>>
>
> +1.
>
>> * `for x in 0..<3 {}` should work (obviously; that's the status quo)
>>
>> * `for x in (0..<20).striding(by: 2)` should work
>>
>> I think this might also handle the concerns that
>> https://github.com/apple/swift-evolution/blob/master/proposals/0051-stride-semantics.md
>> was trying to address.
>>
>> If I thought extreme concision was important for this application, I'd be
>> proposing something like
>>
>> for x in 0.0..<20.0//1.3 {}
>>
>> but personally, I don't, which is why I propose `.striding(by: x)`
>> rather than simply `.by(x)`, the latter being more open to
>> misinterpretation.
>
> Yeah, `.striding(by: x)` is pretty good.
>
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

-1

I don't see the need for special syntax where a method can be easily used and is more general.

-Thorsten

···

Am 18.04.2016 um 17:28 schrieb Vladimir.S via swift-evolution <swift-evolution@swift.org>:

On 15.04.2016 3:57, Hans Huck via swift-evolution wrote:
> Anyway, why not just make it .step() then, like in Ruby?
>
> Instead of a "by" keyword, I'd be happy with syntactic sugar in the form of
>
> for i in p1..<p2 step x

As for 'step' word: It seems like for now IMO this is the best suggestion : very explicit, anyone knows what "step" means especially in context of loop, clear that "step" belongs to for-in construction(not to range itself).

for i in 0..<10 step 2 {
}

for i in 0..<10 step -2 {
}

for i in 0.1..<10.5 step 0.5 {
}

all are mapped to needed ranges/intervals under the hood
Do you want some custom Range-specific methods to provide steps for loop - no problems, use what you need. But don't force any of us to use (0..<10).striding(by:2) for myriads of simple loops in our code.

I want to see such constructions in our Swift. Who is with me ? :)
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'd reply inline but I'm working around some technical limitations on
the go here. Agreed that anything countable should be good for a Range
that conforms to Collection. Well, anything finite, maybe.

I don't think the domain being finite is important at all. You have
concrete endpoints.

See below about countably infinite ranges.Re hypothetical Countable
protocol:I'm not advocating for another protocol for the numeric
type. I'll take your word for it that they aren't jolly, though I
don't know why.

Then I should explain. I don't want to have both a set of Countable
protocols and a set of Collection protocols, each with forward,
bidrectional and random-access traversal, the former being able t
traverse on their own and the latter being able to traverse via an
associated Index. That would be an unpleasant level of complexity to
impose on users.

The issue as I see it is this: currently, Range is documented as a
collection of *discrete* index values.

Yes, that would change.

If Intervals are going away, does a Range<Float> model a countable set
of Floats with unit stride, a finite set of Floats in the technical
sense that there exists only a finite set of representable numbers, or
an uncountable set?

The latter; we mostly choose to ignore the fact that Floats are not
truly arbitrary real numbers, to match most peoples' mental/programming
models. The FloatingPoint protocol will also expose all the operations
that let you deal with the fact that they are not arbitrary reals.

The former two preserves the current definition of Range as a
collection of discrete values but may be astonishing to users. But, if
we agree that the last scenario is most intuitive,

we do

how then can we make the distinction between a "Range" that represents
an uncountable set of things with an upper and lower bound and one
that represents a countable set of things?

It depends on the characteristics of the range's Bound type. If it's
discrete and Countable, you get the latter kind.

Thinking more on this, expanding Range to floating point types opens
you up to another inconsistency. Can the bounds be -inf and inf?

Yes.

I don't see why that should be a problem for an Interval, but now
we're in for some trouble if you want it for a Range that can be
strided through.

I don't.

How about 0.0 and inf? That makes sense to allow.

Yes.

But why should the ranges I'm allowed to specify be constrained by
what makes sense to stride?

They are not.

So the more I think about it, the more I'm convinced that the logic
for what Range-Interval hybrids can be strided through can't neatly
accommodate floating point types. If you merge Range and Interval,
I still want to be able to specify
`-Double.infinity..<Double.infinity`. But if I can do that, then
Range<Double> shouldn't even have `striding(by:)`.

Right. I think we're on the same page. If we had conditional
conformances, we'd have

  struct Range<T: Comparable>
    : HalfOpenRange { ... }

  extension Range<T: Comparable where T: Countable>
    : HalfOpenRange, Collection { ... }

(and the closed-range variants). Until then, we'll need

  struct RangeOfCountable<T: Comparable where T: Countable>
    : HalfOpenRange, Collection { ... }
  
(and the closed-range variant).

The problem is, how to define Countable? If we had to account for all
the different possible traversals, we'd end up with 8 different Range
types (3 Countable and 1 uncountable, closed and half-open). We're
already in a similar position with 12 Slice types(!) in the new design.

I'm not sure if we can do without that complexity for Slices, but in
the case of Ranges, I think it's probably OK to say Countable refines
Strideable, because we won't have any models of Countable that don't
have random access.

···

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

From: Dave Abrahams via swift-evolution <swift-evolution@swift.org>
Sent: Friday, March 25, 2016 8:11 PM Subject: Re: [swift-evolution]
Feature proposal: Range operator with step To:
<swift-evolution@swift.org>

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

Ah, I think the conceptual muddle arises in the plan
then. Specifically, I'd argue that not all Ranges with Strideable
bounds should conform to Collection.

Conceptually, whether a type can be advanced by some distance
(guaranteed by Strideable) is orthogonal to whether a type has an
obviously correct increment when calling next() on its iterator. Thus,
although *strides* with Strideable bounds should obviously conform to
Collection, Ranges that conform to Collection should be constrained to
types which imply that the Range represents a countable set (as the
mathematicians say) of numbers.

I think any countable set should be OK, regardless of whether the
elements are numbers. Ranges of UnsafePointers, for example, are
countable.

This distinction may come in handy for implementing strides that don't
accumulate error. Striding through a Range that represents a countable
set of elements shouldn't accumulate error and we can use what we
already have--i.e. increment the current value every iteration without
inspecting the value of the starting bound. Striding through a Range
that represents an uncountable set of elements definitely requires
reckoning from the starting bound every iteration.

So, what does this Countable protocol look like? It seems like it would
bring back the Index protocols that are otherwise obviated by this
plan... not a jolly prospect.

--
Dave

I'd reply inline but I'm working around some technical limitations on
the go here. Agreed that anything countable should be good for a Range
that conforms to Collection. Well, anything finite, maybe.

I don't think the domain being finite is important at all. You have
concrete endpoints.

See below about countably infinite ranges.Re hypothetical Countable
protocol:I'm not advocating for another protocol for the numeric
type. I'll take your word for it that they aren't jolly, though I
don't know why.

Then I should explain. I don't want to have both a set of Countable
protocols and a set of Collection protocols, each with forward,
bidrectional and random-access traversal, the former being able t
traverse on their own and the latter being able to traverse via an
associated Index. That would be an unpleasant level of complexity to
impose on users.

The issue as I see it is this: currently, Range is documented as a
collection of *discrete* index values.

Yes, that would change.

If Intervals are going away, does a Range<Float> model a countable set
of Floats with unit stride, a finite set of Floats in the technical
sense that there exists only a finite set of representable numbers, or
an uncountable set?

The latter; we mostly choose to ignore the fact that Floats are not
truly arbitrary real numbers, to match most peoples' mental/programming
models. The FloatingPoint protocol will also expose all the operations
that let you deal with the fact that they are not arbitrary reals.

The former two preserves the current definition of Range as a
collection of discrete values but may be astonishing to users. But, if
we agree that the last scenario is most intuitive,

we do

how then can we make the distinction between a "Range" that represents
an uncountable set of things with an upper and lower bound and one
that represents a countable set of things?

It depends on the characteristics of the range's Bound type. If it's
discrete and Countable, you get the latter kind.

Thinking more on this, expanding Range to floating point types opens
you up to another inconsistency. Can the bounds be -inf and inf?

Yes.

I don't see why that should be a problem for an Interval, but now
we're in for some trouble if you want it for a Range that can be
strided through.

I don't.

How about 0.0 and inf? That makes sense to allow.

Yes.

But why should the ranges I'm allowed to specify be constrained by
what makes sense to stride?

They are not.

So the more I think about it, the more I'm convinced that the logic
for what Range-Interval hybrids can be strided through can't neatly
accommodate floating point types. If you merge Range and Interval,
I still want to be able to specify
`-Double.infinity..<Double.infinity`. But if I can do that, then
Range<Double> shouldn't even have `striding(by:)`.

Right. I think we're on the same page. If we had conditional
conformances, we'd have

  struct Range<T: Comparable>
    : HalfOpenRange { ... }

  extension Range<T: Comparable where T: Countable>
    : HalfOpenRange, Collection { ... }

(and the closed-range variants). Until then, we'll need

  struct RangeOfCountable<T: Comparable where T: Countable>
    : HalfOpenRange, Collection { ... }

(and the closed-range variant).

The problem is, how to define Countable? If we had to account for all
the different possible traversals, we'd end up with 8 different Range
types (3 Countable and 1 uncountable, closed and half-open). We're
already in a similar position with 12 Slice types(!) in the new design.

I'm not sure if we can do without that complexity for Slices, but in
the case of Ranges, I think it's probably OK to say Countable refines
Strideable, because we won't have any models of Countable that don't
have random access.

From: Dave Abrahams via swift-evolution <swift-evolution@swift.org>
Sent: Friday, March 25, 2016 8:11 PM Subject: Re: [swift-evolution]
Feature proposal: Range operator with step To:
<swift-evolution@swift.org>

...<schnipp 19>...

···

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

on Fri Mar 25 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

Ah, I think the conceptual muddle arises in the plan
then. Specifically, I'd argue that not all Ranges with Strideable
bounds should conform to Collection.

Conceptually, whether a type can be advanced by some distance
(guaranteed by Strideable) is orthogonal to whether a type has an
obviously correct increment when calling next() on its iterator. Thus,
although *strides* with Strideable bounds should obviously conform to
Collection, Ranges that conform to Collection should be constrained to
types which imply that the Range represents a countable set (as the
mathematicians say) of numbers.

I think any countable set should be OK, regardless of whether the
elements are numbers. Ranges of UnsafePointers, for example, are
countable.

This distinction may come in handy for implementing strides that don't
accumulate error. Striding through a Range that represents a countable
set of elements shouldn't accumulate error and we can use what we
already have--i.e. increment the current value every iteration without
inspecting the value of the starting bound. Striding through a Range
that represents an uncountable set of elements definitely requires
reckoning from the starting bound every iteration.

So, what does this Countable protocol look like? It seems like it would
bring back the Index protocols that are otherwise obviated by this
plan... not a jolly prospect.

--
Dave

Floating-point seconds (as NSTimeIntervals) are the natural Strideable.Stride, but it's not particularly clear to me that you want 1 second to be a default stride. It's the default you would guess, but it's not actually a particularly useful default.

Any fixed-time-period stride with dates is fraught with peril. Not every day is 24 hours, not every minute is 60 seconds, etc. Working with dates requires enough special domain knowledge that I think it'd be harmful to try to genericize numeric concepts over it.

While this is true, "ten seconds from now" is always ten seconds from now, and "seconds between date1 and date2" is always the same number of seconds. There is a basic level of time measurement and manipulation which is completely independent of time zones and calendars; that's what NSDate and NSTimeInterval represent. They are needed fairly often, and they are perfectly compatible with Strideable's semantics.

···

--
Brent Royal-Gordon
Architechies

Thorsten Seitz via swift-evolution <swift-evolution@...> writes:

-1

I don't see the need for special syntax where a method can be easily used

and is more general.

-Thorsten

That, dear Thorsten, is a non-argument. Why? Let's see, how about "I don't
see the need for a For-loop where a While-loop can be easily used and is
more general."

The "special syntax" summarized below by Vladimir is absolutely justified,
because

a) Zipf's Law and
b) forcing people to use convoluted OOP notation for basic, iterative tasks
is simply offensive.

-- Hans

>
> > Anyway, why not just make it .step() then, like in Ruby?
> >
> > Instead of a "by" keyword, I'd be happy with syntactic sugar in the

form of

> >
> > for i in p1..<p2 step x
>
> As for 'step' word: It seems like for now IMO this is the best

suggestion : very explicit, anyone knows what

"step" means especially in context of loop, clear that "step" belongs to

for-in construction(not to

range itself).
>
> for i in 0..<10 step 2 {
> }
>
> for i in 0..<10 step -2 {
> }
>
> for i in 0.1..<10.5 step 0.5 {
> }
>
> all are mapped to needed ranges/intervals under the hood
> Do you want some custom Range-specific methods to provide steps for loop

- no problems, use what you need.

But don't force any of us to use (0..<10).striding(by:2) for myriads of

simple loops in our code.

···

> Am 18.04.2016 um 17:28 schrieb Vladimir.S via swift-evolution <swift-evolution <at> swift.org>:
> On 15.04.2016 3:57, Hans Huck via swift-evolution wrote:
>
> I want to see such constructions in our Swift. Who is with me ? :)