[swift-evolution] Feature proposal: Range operator with step

Xiaodi Wu xiaodi.wu at gmail.com
Thu Mar 31 17:23:46 CDT 2016


All true. I call that Erica's solution because her proposal is where I
first found it sketched out.

I'm not convinced that Erica's solution is definitely the right answer
because:

(a) Use of an iteration counter of type Int to stride through Doubles is an
implementation detail which is not an obviously correct choice; users might
find it surprising that how many steps they get for StrideTo<Double> is
constrained by Int.max

(b) I'm not completely certain that there is no use case for a loop with
more than Int.max steps so long as you break before the end, so I'm not
completely certain that an error right off the bat is the most ideal
behavior; for example, someone may wish to increment by a user-supplied
epsilon from one user-supplied value to another but break after a certain
amount of time has elapsed

(c) I agree with you that it's Swiftier to do nothing than to start
returning approximately correct values, but in a scenario such as `for _ in
stride(from: 0, to: DBL_MAX, by: someAbsurdlySmallValue) { }` it may not
matter (I cannot imagine a use case for this ridiculous loop, but for the
sake of argument here let's take it); one alternative solution someone
might propose, for example, would be to fall back to the old
error-accumulating algorithm after the iteration counter has reached its
max possible value

So I guess the feedback I'm interested in is:

- Would you be surprised to find that Stride<Double> may become constrained
by an upper limit in the number of steps?

- If not, would it irk you that such a limit is based on the size of a
totally unrelated numeric type (namely, Int) which is an implementation
detail? Would you prefer that the limit be something related to the nature
of the type itself (for example, a maximum number of steps for
StrideTo<Double> that reflects the maximum exactly representable integer in
a Double)?

- If there is to be an upper limit on steps, would you prefer an error when
the Stride is being initialized or when the iteration counter overflows?

- Would you rather instead be able to stride indefinitely, as is currently
the case in Swift 2, accepting that error will start accumulating at some
point?

On Thu, Mar 31, 2016 at 4:33 PM Howard Lovatt via swift-evolution <
swift-evolution at swift.org> wrote:

> If you define a range as range[i] = first + i * stride where i is an Int
> then this generates an error when there are more than Int_Max steps, see
> code previously posted. The error is generated when the range is formed,
> which is ideal since an error part way along an iteration or a never ending
> iteration would be difficult to track down.
>
> On Friday, 1 April 2016, Stephen Canon via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>>
>> > On Mar 31, 2016, at 11:16 AM, Rainer Brockerhoff via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> >
>> > On 3/31/16 15:06, Dave Abrahams via swift-evolution wrote:
>> >>
>> >> on Thu Mar 31 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:
>> >>
>> >>> Thoughts on an edge case: so long as it's possible to use
>> >>> `stride(from:to:by:)` with Double, we'll need to figure out what
>> >>> happens when you have `stride(from: 0.0, to: DBL_MAX, by: DBL_MIN)`.
>> >>> Bounds may be unknown at compile time, obviously.
>> >>>
>> >>> Currently (this is by reasoning through the code, not actually
>> >>> observing it run), `for i in stride(from: 0.0, to: DBL_MAX, by:
>> >>> DBL_MIN) { }` degenerates into an infinite loop once you reach
>> >>> sufficient large values such that `current + stride == current`, which
>> >>> for a stride of DBL_MIN should happen pretty quickly.
>> >>>
>> >>> In Erica's proposed floating point Stride, an Int is used to count
>> >>> iterations (and iterations need to be counted in order to avoid
>> >>> accumulating error). Thus, one must break from `for i in stride(from:
>> >>> 0.0, to: DBL_MAX, by: DBL_MIN) { }` before the iteration counter
>> >>> overflows or it will trap. IMO, trapping at some point is fine, but I
>> >>> think a limit of Int.max iterations might be rather arbitrary for a
>> >>> StrideTo<Double> (or whatever it will be named) and I'm not sure how
>> >>> one can justify why the behavior of StrideTo<Double> would change from
>> >>> machine to machine based on the size of Int.
>> >>>
>> >>> I've been waffling between using an Int counter as Erica does or a
>> >>> counter of type Strideable.Stride in `StrideTo<Strideable where
>> >>> Strideable.Stride : FloatingPoint>`. In the latter alternative, no
>> >>> trapping occurs, but error begins to accumulate when the iteration
>> >>> counter is too large to represent integers exactly (e.g., 2^53 for
>> >>> Double). In that case, `for i in stride(from: 0.0, to: DBL_MAX, by:
>> >>> DBL_MIN) { }` degenerates into an infinite loop eventually (once
>> >>> `iterationCount + 1.0 == iterationCount`) and never traps, which I'm
>> >>> not sure I like, but a limit of 2^53 iterations bears at least a
>> >>> rational connection to Double and is known at compile time independent
>> >>> of the supplied bounds. We could alternatively return nil on reaching
>> >>> 2^53 iterations, trap, etc.
>> >>>
>> >>> Comments?
>> >>
>> >> I think I want to hear Steve Canon's input on this one.  I defer to him
>> >> on most things numeric.
>> >
>> > In particular, should Steve confirm that the IEEE754 Decimal128 format
>> > is being worked on, and if simple decimal constants like those in
>> >       `for i in stride(from: 0.0, to: DBL_MAX, by: DBL_MIN) { }`
>> > will be type-inferred as Decimal128, all that would "just work".
>>
>> Decimal is something that I would like to see happen.  However, I would
>> not expect any such proposal to result in that loop being type inferred to
>> Decimal, since the to: and by: values are explicitly (binary
>> floating-point) Doubles.
>>
>> I also don’t think that such a loop is particularly useful.  For
>> floating-point types, something like stride(from: T, to: T, steps: Int)
>> seems safer and more workable to me (this is just my immediate reaction, I
>> haven’t thought this through in detail, and am likely to change my mind if
>> someone makes a good case).
>>
>> – Steve
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>
>
> --
> -- Howard.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160331/f8fe79cd/attachment.html>


More information about the swift-evolution mailing list