[Proposal] Safer half-open range operator


(Luis Henrique Borges) #1

This proposal seeks to provide a safer ..< (aka half-open range operator)
in order to avoid **Array index out of range** errors in execution time.

Here is my first draft for this proposal:
https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

In short, doing that in Swift causes a runtime error:

let a = [1,2,3]
let b = a[0..<5]
print(b)

Error running code:
fatal error: Array index out of range

The proposed solution is to slice the array returning all elements that are
below the half-open operator, even though the number of elements is lesser
than the ending of the half-open operator. So the example above would
return [1,2,3].
We can see this very behaviour in other languages, such as Python and Ruby
as shown in the proposal draft.

This would eliminate the need for verifications on the array size before
slicing it -- and consequently runtime errors in cases when the programmer
didn't.

Viewing that it is my very first proposal, any feedback will be helpful.
Thanks!

Luis Henrique Borges
@luishborges


(Haravikk) #2

I like the idea in theory, but the question is; is it really safer to return a result that the developer may not have wanted, versus an error indicating that a mistake may have been made? I wonder if perhaps there could be an alternative, such as a variation of the operator like so:

  let b = a [0 &..< 5] // Equivalent to let b = a[0 ..< min(5, a.endIndex)], becomes let b = a[0 ..< 3]

I’m just not sure that we can assume that an array index out of range error is okay without some kind of indication from the developer, as otherwise we could end up returning a partial slice, which could end up causing an error elsewhere where the size of the slice is assumed to be 5 but isn’t.

···

On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via swift-evolution <swift-evolution@swift.org> wrote:

This proposal seeks to provide a safer ..< (aka half-open range operator) in order to avoid **Array index out of range** errors in execution time.

Here is my first draft for this proposal: https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

In short, doing that in Swift causes a runtime error:
let a = [1,2,3]
let b = a[0..<5]
print(b)

> Error running code:
> fatal error: Array index out of range

The proposed solution is to slice the array returning all elements that are below the half-open operator, even though the number of elements is lesser than the ending of the half-open operator. So the example above would return [1,2,3].
We can see this very behaviour in other languages, such as Python and Ruby as shown in the proposal draft.

This would eliminate the need for verifications on the array size before slicing it -- and consequently runtime errors in cases when the programmer didn't.

Viewing that it is my very first proposal, any feedback will be helpful.

Thanks!

Luis Henrique Borges
@luishborges
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Taras Zakharko) #3

I do not think that this should be included in the default library as it is inconsistent with the behavior we generally have on collections (where user is responsible for correct indexing). However, it is quite trivial to define a new subscript operation, e.g. subscript(safe: Range)

— Taras

···

On 11 Apr 2016, at 14:23, Luis Henrique B. Sousa via swift-evolution <swift-evolution@swift.org> wrote:

This proposal seeks to provide a safer ..< (aka half-open range operator) in order to avoid **Array index out of range** errors in execution time.

Here is my first draft for this proposal: https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

In short, doing that in Swift causes a runtime error:
let a = [1,2,3]
let b = a[0..<5]
print(b)

> Error running code:
> fatal error: Array index out of range

The proposed solution is to slice the array returning all elements that are below the half-open operator, even though the number of elements is lesser than the ending of the half-open operator. So the example above would return [1,2,3].
We can see this very behaviour in other languages, such as Python and Ruby as shown in the proposal draft.

This would eliminate the need for verifications on the array size before slicing it -- and consequently runtime errors in cases when the programmer didn't.

Viewing that it is my very first proposal, any feedback will be helpful.

Thanks!

Luis Henrique Borges
@luishborges
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pyry Jahkola) #4

In the swift-3-indexing-model branch <https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Range.swift#L94>, you can clamp a range just like you could clamp intervals in Swift 2. So the following will work in the way you preferred:

    let b = a[a.indices.clamped(to: 0 ..< 5)]

It was suggested to extend `Collection` with a subscript like `a[safe: 0 ..< 5]` which resembles the current subsequence subscript <https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L82>. Alternatively, we could bring collections even closer to ranges by extending them with the equivalent `.clamped(to:)` method:

    let b = a.clamped(to: 0 ..< 5) // "safe" subsequence

— Pyry

···

On 11 Apr 2016, at 15:23, Luis Henrique B. Sousa via swift-evolution <swift-evolution@swift.org> wrote:
let a = [1,2,3]
let b = a[0..<5]
print(b)


(Dave Abrahams) #5

I like the idea in theory, but the question is; is it really safer to return a
result that the developer may not have wanted, versus an error indicating that a
mistake may have been made?

That's exactly the question. We've considered doing it both ways.

···

on Mon Apr 11 2016, Haravikk <swift-evolution@swift.org> wrote:

I wonder if perhaps there could be an alternative, such as a variation
of the operator like so:

let b = a [0 &..< 5] // Equivalent to let b = a[0 ..< min(5, a.endIndex)],
becomes let b = a[0 ..< 3]

I’m just not sure that we can assume that an array index out of range error is
okay without some kind of indication from the developer, as otherwise we could
end up returning a partial slice, which could end up causing an error elsewhere
where the size of the slice is assumed to be 5 but isn’t.

    On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via swift-evolution > <swift-evolution@swift.org> wrote:

    This proposal seeks to provide a safer ..< (aka half-open range operator) in
    order to avoid **Array index out of range** errors in execution time.

    Here is my first draft for this proposal:
    https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

    In short, doing that in Swift causes a runtime error:

    let a = [1,2,3]
    let b = a[0..<5]
    print(b)

    > Error running code:
    > fatal error: Array index out of range

    The proposed solution is to slice the array returning all elements that are
    below the half-open operator, even though the number of elements is lesser
    than the ending of the half-open operator. So the example above would return
    [1,2,3].
    We can see this very behaviour in other languages, such as Python and Ruby
    as shown in the proposal draft.

    This would eliminate the need for verifications on the array size before
    slicing it -- and consequently runtime errors in cases when the programmer
    didn't.

    Viewing that it is my very first proposal, any feedback will be helpful.

    Thanks!

    Luis Henrique Borges
    @luishborges
    _______________________________________________
    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


(Vladimir) #6

+1 for the idea "in general". But I also think that explicit is better than implicit, especially if we deal with possible errors. Just like we work in Swift with integer overflow : '+' will generate run time error, but saying &+ we point Swift that we know what we do.

but.. what we'll have in case a[-1 &..< 5]? should this raise error or become [0 ..< 3] ? I think, the latter.

···

On 11.04.2016 17:02, Haravikk via swift-evolution wrote:

I like the idea in theory, but the question is; is it really safer to
return a result that the developer may not have wanted, versus an error
indicating that a mistake may have been made? I wonder if perhaps there
could be an alternative, such as a variation of the operator like so:

let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5, a.endIndex)],
becomes let b = a[0 ..< 3]

I’m just not sure that we can assume that an array index out of range error
is okay without some kind of indication from the developer, as otherwise we
could end up returning a partial slice, which could end up causing an error
elsewhere where the size of the slice is assumed to be 5 but isn’t.

On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This proposal seeks to provide a safer ..< (aka half-open range operator)
in order to avoid **Array index out of range** errors in execution time.

Here is my first draft for this proposal:
https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

In short, doing that in Swift causes a runtime error:

leta =[1,2,3]
letb =a[0..<5]
print(b)

> Error running code:
> fatal error: Array index out of range

The proposed solution is to slice the array returning all elements that
are below the half-open operator, even though the number of elements is
lesser than the ending of the half-open operator. So the example above
would return [1,2,3].
We can see this very behaviour in other languages, such as Python and
Ruby as shown in the proposal draft.

This would eliminate the need for verifications on the array size before
slicing it -- and consequently runtime errors in cases when the
programmer didn't.

Viewing that it is my very first proposal, any feedback will be helpful.

Thanks!

Luis Henrique Borges
@luishborges
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Chris Lattner) #7

Right. There is a natural tension here between:

1) “fail fast” - so that an error is easily detected and reasoned about by the programmer, and
2) "blunder on” - hope that an error didn’t matter in practice, at the cost to making actual errors harder to diagnose.

-Chris

···

On Apr 11, 2016, at 12:30 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Mon Apr 11 2016, Haravikk <swift-evolution@swift.org> wrote:

I like the idea in theory, but the question is; is it really safer to return a
result that the developer may not have wanted, versus an error indicating that a
mistake may have been made?

That's exactly the question. We've considered doing it both ways.


(Vladimir) #8

Is it really great to have a[a.indices.clamped(to: 0 ..< 5)]
instead of a clear a[truncate: 0 ..< 5] ?
and if it is not "a" but "arrayOfSomeValues" we have
arrayOfSomeValues[arrayOfSomeValues.indices.clamped(to: 0 ..< 5)]
Don't feel this is nice.

Is it really so wrong to have additional(to "direct" functions like "indices.clamped" ) handy and nice-looking methods/subscripts in language?

IMO we all want to have great language. It should be great to code in such language. Is it great and enjoyable to have strange long construction instead of handy,clear and explicit expression?
Why don't improve the language in all possible area where we can improve it? I believe we should improve.

···

On 13.04.2016 14:09, Pyry Jahkola via swift-evolution wrote:

On 11 Apr 2016, at 15:23, Luis Henrique B. Sousa via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

leta =[1,2,3]
letb =a[0..<5]
print(b)

In the swift-3-indexing-model branch
<https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Range.swift#L94>,
you can /clamp/ a range just like you could clamp intervals in Swift 2. So
the following will work in the way you preferred:

     let b = a[a.indices.clamped(to: 0 ..< 5)]

It was suggested to extend `Collection` with a subscript like `a[safe: 0
..< 5]` which resembles the current subsequence subscript
<https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L82>. Alternatively,
we could bring collections even closer to ranges by extending them with the
equivalent `.clamped(to:)` method:

     let b = a.clamped(to: 0 ..< 5) // "safe" subsequence

— Pyry

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


(Luis Henrique Borges) #9

The idea of having a new operator following the principles of overflow
operators looks great. Two distinct operators doing implicit and explicitly
might really be a good way to go; it would be concise and wouldn't look
like some magic happened behind the scenes. I'd like to hear more opinions
about it.

what we'll have in case a[-1 &..< 5]? should this raise error or become

[0 ..< 3] ? I think, the latter.
I agree here, I'd choose the latter.

From my perspective, the behaviour I'm proposing is what a considerable

number of users expect, especially if coming from other languages that
follow that path. Of course I'm not comparing languages here, but
considering the Swift principles of being a safer language, in my opinion
we'd rather have a partial slice than a crash in execution time (when the
user is not totally aware of it).

Many thanks for all your additions so far. It's really good to see that
these things are not set in stone yet.

- Luis

···

On Apr 11, 2016 4:21 PM, "Vladimir.S via swift-evolution" < swift-evolution@swift.org> wrote:

+1 for the idea "in general". But I also think that explicit is better
than implicit, especially if we deal with possible errors. Just like we
work in Swift with integer overflow : '+' will generate run time error, but
saying &+ we point Swift that we know what we do.

but.. what we'll have in case a[-1 &..< 5]? should this raise error or
become [0 ..< 3] ? I think, the latter.

On 11.04.2016 17:02, Haravikk via swift-evolution wrote:

I like the idea in theory, but the question is; is it really safer to
return a result that the developer may not have wanted, versus an error
indicating that a mistake may have been made? I wonder if perhaps there
could be an alternative, such as a variation of the operator like so:

let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5, a.endIndex)],
becomes let b = a[0 ..< 3]

I’m just not sure that we can assume that an array index out of range
error
is okay without some kind of indication from the developer, as otherwise
we
could end up returning a partial slice, which could end up causing an
error
elsewhere where the size of the slice is assumed to be 5 but isn’t.

On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This proposal seeks to provide a safer ..< (aka half-open range operator)
in order to avoid **Array index out of range** errors in execution time.

Here is my first draft for this proposal:

https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

In short, doing that in Swift causes a runtime error:

leta =[1,2,3]
letb =a[0..<5]
print(b)

> Error running code:
> fatal error: Array index out of range

The proposed solution is to slice the array returning all elements that
are below the half-open operator, even though the number of elements is
lesser than the ending of the half-open operator. So the example above
would return [1,2,3].
We can see this very behaviour in other languages, such as Python and
Ruby as shown in the proposal draft.

This would eliminate the need for verifications on the array size before
slicing it -- and consequently runtime errors in cases when the
programmer didn't.

Viewing that it is my very first proposal, any feedback will be helpful.

Thanks!

Luis Henrique Borges
@luishborges
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

_______________________________________________

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


(Luis Henrique Borges) #10

Many thanks @Pyry, it's great to see those changes coming in swift 3. The
examples using *clamp* you mentioned here would do what I'm proposing, but
I totally agree with @Vladimir that we could have a more clear and
*swift-ly* way to concisely wrap those operations.

The behaviour pointed out by him looks very nice and doable to me.

a = [1,2,3]
a[-1..<6] - raises runtime error (right behavior by default, doesn't affect
existing code)
a[truncate: -1..<6] - produces [1,2,3] (the very behaviour I proposed
initially)
a[safe: -1..<6] - produces nil (i.e [T]?) (no runtime errors and makes it
easy to handle unexpected results)

I'd like to hear more opinions before I update my proposal with those new
subscript methods (instead of a different operator, or added as an
alternative considered).
Thanks

- Luis

···

On Wed, Apr 13, 2016 at 2:11 PM, Vladimir.S via swift-evolution < swift-evolution@swift.org> wrote:

Is it really great to have a[a.indices.clamped(to: 0 ..< 5)]
instead of a clear a[truncate: 0 ..< 5] ?
and if it is not "a" but "arrayOfSomeValues" we have
arrayOfSomeValues[arrayOfSomeValues.indices.clamped(to: 0 ..< 5)]
Don't feel this is nice.

Is it really so wrong to have additional(to "direct" functions like
"indices.clamped" ) handy and nice-looking methods/subscripts in language?

IMO we all want to have great language. It should be great to code in such
language. Is it great and enjoyable to have strange long construction
instead of handy,clear and explicit expression?
Why don't improve the language in all possible area where we can improve
it? I believe we should improve.

On 13.04.2016 14:09, Pyry Jahkola via swift-evolution wrote:

On 11 Apr 2016, at 15:23, Luis Henrique B. Sousa via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

leta =[1,2,3]
letb =a[0..<5]
print(b)

In the swift-3-indexing-model branch

<
https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Range.swift#L94
>,
you can /clamp/ a range just like you could clamp intervals in Swift 2. So
the following will work in the way you preferred:

     let b = a[a.indices.clamped(to: 0 ..< 5)]

It was suggested to extend `Collection` with a subscript like `a[safe: 0
..< 5]` which resembles the current subsequence subscript
<
https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L82>.
Alternatively,
we could bring collections even closer to ranges by extending them with
the
equivalent `.clamped(to:)` method:

     let b = a.clamped(to: 0 ..< 5) // "safe" subsequence

— Pyry

_______________________________________________
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


(Pyry Jahkola) #11

I don't feel strongly about this. Yes, if this were shorter to express, it would feel like nicer design. But what Haravikk and Chris L. already said seems to me as wiser design.

(@Vladimir: Besides, I'm sure `.clamped(to:)` wasn't invented for this purpose but for doing interval arithmetic on ranges. It just happens to somewhat work here.)

– Would this feature really provide a measurable benefit to developers?
– Under which circumstances do you find yourself with a past-the-end upper bound such as 6 where `a.count == 3`?
– …Let alone a negative start index like `-1`?

I find cases like these to be much more common in languages like Python and Ruby where e.g. `array[-2]` refers to the penultimate element. Swift doesn't seem to want to go there.

For the use cases I can think of, Swift 3—as the proposal currently goes <https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L724-L808>—already offers the following suitable methods:

    array[bounds]
    array.prefix(maxLength) // no precondition
    array.prefix(upTo: index)
    array.prefix(through: index)
    array.dropLast(n) // no precondition
    array.dropFirst(n) // no precondition
    array.suffix(from: index)
    array.suffix(maxLength) // no precondition

If these feel too clumsy to use, maybe we should focus on making them all more convenient. Ideally, that suggestion would apply to all `Collection`s.

— Pyry

···

On 13 Apr 2016, at 17:53, Luis Henrique B. Sousa <lshsousa@gmail.com> wrote:

(…) I totally agree with @Vladimir that we could have a more clear and swift-ly way to concisely wrap those operations.

The behaviour pointed out by him looks very nice and doable to me.

a = [1,2,3]
a[-1..<6] - raises runtime error (right behavior by default, doesn't affect existing code)
a[truncate: -1..<6] - produces [1,2,3] (the very behaviour I proposed initially)
a[safe: -1..<6] - produces nil (i.e [T]?) (no runtime errors and makes it easy to handle unexpected results)


#12

Should this new operator form a new range? How can this range know about the array's indices?

A while ago there was a proposal (unfortunately it was not discussed enough) which introduced safe array indexing:

         array[safe: 3] // returns nil if index out of bounds

So another way to handle this issue would be to make another subscript like:

         array[truncate: -1...6]

Best regards
- Maximilian

···

Am 12.04.2016 um 01:21 schrieb Luis Henrique B. Sousa via swift-evolution <swift-evolution@swift.org>:

The idea of having a new operator following the principles of overflow operators looks great. Two distinct operators doing implicit and explicitly might really be a good way to go; it would be concise and wouldn't look like some magic happened behind the scenes. I'd like to hear more opinions about it.

> what we'll have in case a[-1 &..< 5]? should this raise error or become [0 ..< 3] ? I think, the latter.
I agree here, I'd choose the latter.

From my perspective, the behaviour I'm proposing is what a considerable number of users expect, especially if coming from other languages that follow that path. Of course I'm not comparing languages here, but considering the Swift principles of being a safer language, in my opinion we'd rather have a partial slice than a crash in execution time (when the user is not totally aware of it).

Many thanks for all your additions so far. It's really good to see that these things are not set in stone yet.

- Luis

On Apr 11, 2016 4:21 PM, "Vladimir.S via swift-evolution" <swift-evolution@swift.org> wrote:
+1 for the idea "in general". But I also think that explicit is better than implicit, especially if we deal with possible errors. Just like we work in Swift with integer overflow : '+' will generate run time error, but saying &+ we point Swift that we know what we do.

but.. what we'll have in case a[-1 &..< 5]? should this raise error or become [0 ..< 3] ? I think, the latter.

On 11.04.2016 17:02, Haravikk via swift-evolution wrote:
I like the idea in theory, but the question is; is it really safer to
return a result that the developer may not have wanted, versus an error
indicating that a mistake may have been made? I wonder if perhaps there
could be an alternative, such as a variation of the operator like so:

let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5, a.endIndex)],
becomes let b = a[0 ..< 3]

I’m just not sure that we can assume that an array index out of range error
is okay without some kind of indication from the developer, as otherwise we
could end up returning a partial slice, which could end up causing an error
elsewhere where the size of the slice is assumed to be 5 but isn’t.

On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This proposal seeks to provide a safer ..< (aka half-open range operator)
in order to avoid **Array index out of range** errors in execution time.

Here is my first draft for this proposal:
https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

In short, doing that in Swift causes a runtime error:

leta =[1,2,3]
letb =a[0..<5]
print(b)

> Error running code:
> fatal error: Array index out of range

The proposed solution is to slice the array returning all elements that
are below the half-open operator, even though the number of elements is
lesser than the ending of the half-open operator. So the example above
would return [1,2,3].
We can see this very behaviour in other languages, such as Python and
Ruby as shown in the proposal draft.

This would eliminate the need for verifications on the array size before
slicing it -- and consequently runtime errors in cases when the
programmer didn't.

Viewing that it is my very first proposal, any feedback will be helpful.

Thanks!

Luis Henrique Borges
@luishborges
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

_______________________________________________
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


(Vladimir) #13

(…) I totally agree with @Vladimir that we could have a more clear and
/swift-ly/ way to concisely wrap those operations.

The behaviour pointed out by him looks very nice and doable to me.

a = [1,2,3]
a[-1..<6] - raises runtime error (right behavior by default, doesn't
affect existing code)
a[truncate: -1..<6] - produces [1,2,3] (the very behaviour I proposed
initially)
a[safe: -1..<6] - produces nil (i.e [T]?) (no runtime errors and makes it
easy to handle unexpected results)

I don't feel strongly about this. Yes, if this were shorter to express, it
would feel like /nicer/ design. But what Haravikk and Chris L. already said
seems to me as /wiser/ design.

IMO it is not just nicer, it provides you with handy and explicit alternatives.

In some situations, you are checking bounds and you sure that if you calculated them incorrectly - error will be raised.
But sometimes, you don't need to check exact bounds, probably "take these values, or give me nil of no such".

I can compare this with Dictionary we have in Swift.
Can you say if it is "wise" to return Optional(T) when we calls dict[somekey] ? Probably it is wise to raise error if there is no such key? (to force us to check the key first).

The proposed subscript for special situations when you know you need exactly this behavior to make your code clear and readable and you fully controls code&error flow.

(@Vladimir: Besides, I'm sure `.clamped(to:)` wasn't invented for this
purpose but for doing interval arithmetic on ranges. It just happens to
somewhat work here.)

– Would this feature really provide a measurable benefit to developers?
– Under which circumstances do you find yourself with a past-the-end upper
bound such as 6 where `a.count == 3`?
– …Let alone a /negative/ start index like `-1`?

I find cases like these to be much more common in languages like Python and
Ruby where e.g. `array[-2]` refers to the penultimate element. Swift
doesn't seem to want to go there.

Each good feature will provide benefit to developers. For those, who work a lot with arrays/bounds/slices/copies this will provide measurable benefit, IMO.
Can we live without such improvement? Absolutely. Are there more important proposals? Yes. But will this make Swift more elegant, handy, clear? Yes, I believe.

As for "Under which circumstances.." questions. Well.. something like "get +- 5 elements(at max) with center in some index"

let a = [1,2,3,4,5,6]
let index = random(0..<a.count)
let result = a[truncate: index-5...index+5]

or "get 5 elements from index, if no 5 elements from index - return empty array"

let a = [1,2,3,4,5,6]
let index = random(0..<a.count)
if let result = a[safe: index..<index+5] //[Int]?
  {return result}
else
  {return []}

Something like this.

For the use cases I can think of, Swift 3—as the proposal currently goes
<https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L724-L808>—already
offers the following suitable methods:

     array[bounds]
     array.prefix(maxLength)// no precondition
     array.prefix(upTo: index)
     array.prefix(through: index)
     array.dropLast(n)// no precondition
     array.dropFirst(n)// no precondition
     array.suffix(from: index)
     array.suffix(maxLength) // no precondition

If these feel too clumsy to use, maybe we should focus on making them all
more convenient. Ideally, that suggestion would apply to all `Collection`s.

— Pyry

Yes, some variants can be covered by these methods:
array.prefix(maxLength) -> array[truncate: 0..<maxLength]
array.prefix(upTo) -> array[0..<upTo]
array.prefix(through) -> array[0...through]

And some has no good alternatives in subscription:
array.suffix(from: index) -> array[truncate: index...Int.max ??
array.suffix(maxLength) -> array[truncate: hm..

But. As array[bound] returns a copy(slice) of array, it feels natural to have variants of behavior of array[bound], just like you have different variants of prefix() methods.

So it seems for me like this proposal for subscript variants(safe: & truncate:) is good addition to then proposal you pointed to.

···

On 13.04.2016 19:59, Pyry Jahkola wrote:

On 13 Apr 2016, at 17:53, Luis Henrique B. Sousa <lshsousa@gmail.com >> <mailto:lshsousa@gmail.com>> wrote:


(Dave Abrahams) #14

Should this new operator form a new range? How can this range know about the
array's indices?

A while ago there was a proposal (unfortunately it was not discussed enough)
which introduced safe array indexing:

array[safe: 3] // returns nil if index out of bounds

Wrong label, but I wouldn't be opposed to adding such an operator for
all Collections.

So another way to handle this issue would be to make another subscript like:

array[truncate: -1...6]

That approach makes sense too. But then do we add

  x[python: 0..<-2] // all but the last two elements?

;^)

···

on Wed Apr 13 2016, Maximilian Hünenberger <swift-evolution@swift.org> wrote:

Best regards
- Maximilian

Am 12.04.2016 um 01:21 schrieb Luis Henrique B. Sousa via swift-evolution > <swift-evolution@swift.org>:

        The idea of having a new operator following the principles of overflow
    operators looks great. Two distinct operators doing implicit and explicitly
    might really be a good way to go; it would be concise and wouldn't look like
    some magic happened behind the scenes. I'd like to hear more opinions about
    it.

    > what we'll have in case a[-1 &..< 5]? should this raise error or become [0
    ..< 3] ? I think, the latter.
    I agree here, I'd choose the latter.

    From my perspective, the behaviour I'm proposing is what a considerable
    number of users expect, especially if coming from other languages that
    follow that path. Of course I'm not comparing languages here, but
    considering the Swift principles of being a safer language, in my opinion
    we'd rather have a partial slice than a crash in execution time (when the
    user is not totally aware of it).

    Many thanks for all your additions so far. It's really good to see that
    these things are not set in stone yet.

    - Luis

    On Apr 11, 2016 4:21 PM, "Vladimir.S via swift-evolution" > <swift-evolution@swift.org> wrote:

    +1 for the idea "in general". But I also think that explicit is better than
        implicit, especially if we deal with possible errors. Just like we work
        in Swift with integer overflow : '+' will generate run time error, but
        saying &+ we point Swift that we know what we do.

        but.. what we'll have in case a[-1 &..< 5]? should this raise error or
        become [0 ..< 3] ? I think, the latter.

        On 11.04.2016 17:02, Haravikk via swift-evolution wrote:

        I like the idea in theory, but the question is; is it really safer to
            return a result that the developer may not have wanted, versus an
            error
            indicating that a mistake may have been made? I wonder if perhaps
            there
            could be an alternative, such as a variation of the operator like
            so:

            let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5,
            a.endIndex)],
            becomes let b = a[0 ..< 3]

            I’m just not sure that we can assume that an array index out of
            range error
            is okay without some kind of indication from the developer, as
            otherwise we
            could end up returning a partial slice, which could end up causing
            an error
            elsewhere where the size of the slice is assumed to be 5 but isn’t.

                        On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via > swift-evolution > <swift-evolution@swift.org > <mailto:swift-evolution@swift.org>> > wrote:

                This proposal seeks to provide a safer ..< (aka half-open range
                operator)
                in order to avoid **Array index out of range** errors in
                execution time.

                Here is my first draft for this proposal:
                https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

                In short, doing that in Swift causes a runtime error:

                leta =[1,2,3]
                letb =a[0..<5]
                print(b)

                > Error running code:
                > fatal error: Array index out of range

                The proposed solution is to slice the array returning all
                elements that
                are below the half-open operator, even though the number of
                elements is
                lesser than the ending of the half-open operator. So the example
                above
                would return [1,2,3].
                We can see this very behaviour in other languages, such as
                Python and
                Ruby as shown in the proposal draft.

                This would eliminate the need for verifications on the array
                size before
                slicing it -- and consequently runtime errors in cases when the
                programmer didn't.

                Viewing that it is my very first proposal, any feedback will be
                helpful.

                Thanks!

                Luis Henrique Borges
                @luishborges
                _______________________________________________
                swift-evolution mailing list
                swift-evolution@swift.org
                <mailto: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

        _______________________________________________
        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

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

--
Dave


(Vladimir) #15

The problem the "a[i &..< j]" is trying to solve is to allow us to work with array bounds without errors, even if i/j is incorrect, when we explicitly allows this.

As for your question, yes, it seems like there is a problem :slight_smile:
"i &..< j" should become a new Range. But such range knows nothing about array and its bounds. Probably such operator is not the best idea.

It seems I'd prefer in this case some kind of a[truncate: -1..<6] and probably a[safe: -1..<6] - which returns nil if range is incorrect.
So, in this case we'll have these methods and behavior:
a=[1,2,3]
a[-1..<6] - raises runtime error
a[truncate: -1..<6] - produces [1,2,3]
a[safe: -1..<6] - produces nil (i.e [T]?)

Seems like very handy and explicit. Right behavior by default(raises error). Opinions?

···

On 13.04.2016 13:52, Maximilian Hünenberger via swift-evolution wrote:

Should this new operator form a new range? How can this range know about
the array's indices?

A while ago there was a proposal (unfortunately it was not discussed
enough) which introduced safe array indexing:

          array[safe: 3] // returns nil if index out of bounds

So another way to handle this issue would be to make another subscript like:

          array[truncate: -1...6]

Best regards
- Maximilian

Am 12.04.2016 um 01:21 schrieb Luis Henrique B. Sousa via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

The idea of having a new operator following the principles of overflow
operators looks great. Two distinct operators doing implicit and
explicitly might really be a good way to go; it would be concise and
wouldn't look like some magic happened behind the scenes. I'd like to
hear more opinions about it.

> what we'll have in case a[-1 &..< 5]? should this raise error or become
[0 ..< 3] ? I think, the latter.
I agree here, I'd choose the latter.

From my perspective, the behaviour I'm proposing is what a considerable
number of users expect, especially if coming from other languages that
follow that path. Of course I'm not comparing languages here, but
considering the Swift principles of being a safer language, in my opinion
we'd rather have a partial slice than a crash in execution time (when the
user is not totally aware of it).

Many thanks for all your additions so far. It's really good to see that
these things are not set in stone yet.

- Luis

On Apr 11, 2016 4:21 PM, "Vladimir.S via swift-evolution" >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

    +1 for the idea "in general". But I also think that explicit is
    better than implicit, especially if we deal with possible errors.
    Just like we work in Swift with integer overflow : '+' will generate
    run time error, but saying &+ we point Swift that we know what we do.

    but.. what we'll have in case a[-1 &..< 5]? should this raise error
    or become [0 ..< 3] ? I think, the latter.

    On 11.04.2016 17:02, Haravikk via swift-evolution wrote:

        I like the idea in theory, but the question is; is it really safer to
        return a result that the developer may not have wanted, versus an
        error
        indicating that a mistake may have been made? I wonder if perhaps
        there
        could be an alternative, such as a variation of the operator like so:

        let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5,
        a.endIndex)],
        becomes let b = a[0 ..< 3]

        I’m just not sure that we can assume that an array index out of
        range error
        is okay without some kind of indication from the developer, as
        otherwise we
        could end up returning a partial slice, which could end up
        causing an error
        elsewhere where the size of the slice is assumed to be 5 but isn’t.

            On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via >> swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> <mailto:swift-evolution@swift.org >> <mailto:swift-evolution@swift.org>>> wrote:

            This proposal seeks to provide a safer ..< (aka half-open
            range operator)
            in order to avoid **Array index out of range** errors in
            execution time.

            Here is my first draft for this proposal:
            https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

            In short, doing that in Swift causes a runtime error:

            leta =[1,2,3]
            letb =a[0..<5]
            print(b)

            > Error running code:
            > fatal error: Array index out of range

            The proposed solution is to slice the array returning all
            elements that
            are below the half-open operator, even though the number of
            elements is
            lesser than the ending of the half-open operator. So the
            example above
            would return [1,2,3].
            We can see this very behaviour in other languages, such as
            Python and
            Ruby as shown in the proposal draft.

            This would eliminate the need for verifications on the array
            size before
            slicing it -- and consequently runtime errors in cases when the
            programmer didn't.

            Viewing that it is my very first proposal, any feedback will
            be helpful.

            Thanks!

            Luis Henrique Borges
            @luishborges
            _______________________________________________
            swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org>
            <mailto:swift-evolution@swift.org
            <mailto:swift-evolution@swift.org>>
            https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Luis Henrique Borges) #16

Another common application would be on pagination systems. For example,
this function that I just found randomly:
https://github.com/MrAlek/PagedArray/blob/bf64cbb140cf8bd109483dd749ac40a5f4531dfd/Source/PagedArray.swift#L88

public func indexes(pageIndex: Int) -> Range<Index> {
    assert(pageIndex >= startPageIndex && pageIndex <= lastPageIndex, "Page
index out of bounds")

    let startIndex: Index = (pageIndex-startPageIndex)*pageSize
    let endIndex: Index
    if pageIndex == lastPageIndex {
        endIndex = count
    } else {
        endIndex = startIndex+pageSize
    }

    return (startIndex..<endIndex)
}

wouldn't be required anymore before accessing the array, having simply
something like

let current = pageIndex * pageSize
array[safe: (current - pageSize) ..< (current + pageSize)]

(or *truncate* according to the user expectation) instead, which in my
opinion looks much more elegant and handy.

Regards,

- Luis

···

On Wed, Apr 13, 2016 at 7:37 PM, Vladimir.S via swift-evolution < swift-evolution@swift.org> wrote:

On 13.04.2016 19:59, Pyry Jahkola wrote:

On 13 Apr 2016, at 17:53, Luis Henrique B. Sousa <lshsousa@gmail.com >>> <mailto:lshsousa@gmail.com>> wrote:

(…) I totally agree with @Vladimir that we could have a more clear and
/swift-ly/ way to concisely wrap those operations.

The behaviour pointed out by him looks very nice and doable to me.

a = [1,2,3]
a[-1..<6] - raises runtime error (right behavior by default, doesn't
affect existing code)
a[truncate: -1..<6] - produces [1,2,3] (the very behaviour I proposed
initially)
a[safe: -1..<6] - produces nil (i.e [T]?) (no runtime errors and makes it
easy to handle unexpected results)

I don't feel strongly about this. Yes, if this were shorter to express, it
would feel like /nicer/ design. But what Haravikk and Chris L. already
said
seems to me as /wiser/ design.

IMO it is not just nicer, it provides you with handy and explicit
alternatives.

In some situations, you are checking bounds and you sure that if you
calculated them incorrectly - error will be raised.
But sometimes, you don't need to check exact bounds, probably "take these
values, or give me nil of no such".

I can compare this with Dictionary we have in Swift.
Can you say if it is "wise" to return Optional(T) when we calls
dict[somekey] ? Probably it is wise to raise error if there is no such key?
(to force us to check the key first).

The proposed subscript for special situations when you know you need
exactly this behavior to make your code clear and readable and you fully
controls code&error flow.

(@Vladimir: Besides, I'm sure `.clamped(to:)` wasn't invented for this
purpose but for doing interval arithmetic on ranges. It just happens to
somewhat work here.)

– Would this feature really provide a measurable benefit to developers?
– Under which circumstances do you find yourself with a past-the-end upper
bound such as 6 where `a.count == 3`?
– …Let alone a /negative/ start index like `-1`?

I find cases like these to be much more common in languages like Python
and
Ruby where e.g. `array[-2]` refers to the penultimate element. Swift
doesn't seem to want to go there.

Each good feature will provide benefit to developers. For those, who work
a lot with arrays/bounds/slices/copies this will provide measurable
benefit, IMO.
Can we live without such improvement? Absolutely. Are there more important
proposals? Yes. But will this make Swift more elegant, handy, clear? Yes, I
believe.

As for "Under which circumstances.." questions. Well.. something like "get
+- 5 elements(at max) with center in some index"

let a = [1,2,3,4,5,6]
let index = random(0..<a.count)
let result = a[truncate: index-5...index+5]

or "get 5 elements from index, if no 5 elements from index - return empty
array"

let a = [1,2,3,4,5,6]
let index = random(0..<a.count)
if let result = a[safe: index..<index+5] //[Int]?
{return result}
else
{return []}

Something like this.

For the use cases I can think of, Swift 3—as the proposal currently goes

<
https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L724-L808
>—already
offers the following suitable methods:

     array[bounds]
     array.prefix(maxLength)// no precondition
     array.prefix(upTo: index)
     array.prefix(through: index)
     array.dropLast(n)// no precondition
     array.dropFirst(n)// no precondition
     array.suffix(from: index)
     array.suffix(maxLength) // no precondition

If these feel too clumsy to use, maybe we should focus on making them all
more convenient. Ideally, that suggestion would apply to all
`Collection`s.

— Pyry

Yes, some variants can be covered by these methods:
array.prefix(maxLength) -> array[truncate: 0..<maxLength]
array.prefix(upTo) -> array[0..<upTo]
array.prefix(through) -> array[0...through]

And some has no good alternatives in subscription:
array.suffix(from: index) -> array[truncate: index...Int.max ??
array.suffix(maxLength) -> array[truncate: hm..

But. As array[bound] returns a copy(slice) of array, it feels natural to
have variants of behavior of array[bound], just like you have different
variants of prefix() methods.

So it seems for me like this proposal for subscript variants(safe: &
truncate:) is good addition to then proposal you pointed to.

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


(Daniel Quirino) #17

Totally agreed with you guys, for me the matter question here is:

Why should we care about language details instead what the app really have
to do?

Keeping in mind that kind of stuff doesn't help, the focus should be in
their functionalities and all that could be done to get handy and keep a
clearly code should be done, I think we need less C/C++/Obj-C style on
swift and I let a question:

What controlling arrays bounds stands for? being that swift could do this
behind the scenes.

···

Em quarta-feira, 13 de abril de 2016, Luis Henrique B. Sousa via swift-evolution <swift-evolution@swift.org> escreveu:

Another common application would be on pagination systems. For example,
this function that I just found randomly:

https://github.com/MrAlek/PagedArray/blob/bf64cbb140cf8bd109483dd749ac40a5f4531dfd/Source/PagedArray.swift#L88

public func indexes(pageIndex: Int) -> Range<Index> {
    assert(pageIndex >= startPageIndex && pageIndex <= lastPageIndex,
"Page index out of bounds")

    let startIndex: Index = (pageIndex-startPageIndex)*pageSize
    let endIndex: Index
    if pageIndex == lastPageIndex {
        endIndex = count
    } else {
        endIndex = startIndex+pageSize
    }

    return (startIndex..<endIndex)
}

wouldn't be required anymore before accessing the array, having simply
something like

> let current = pageIndex * pageSize
> array[safe: (current - pageSize) ..< (current + pageSize)]

(or *truncate* according to the user expectation) instead, which in my
opinion looks much more elegant and handy.

Regards,

- Luis

On Wed, Apr 13, 2016 at 7:37 PM, Vladimir.S via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

On 13.04.2016 19:59, Pyry Jahkola wrote:

On 13 Apr 2016, at 17:53, Luis Henrique B. Sousa <lshsousa@gmail.com >>>> <javascript:_e(%7B%7D,'cvml','lshsousa@gmail.com');> >>>> <mailto:lshsousa@gmail.com >>>> <javascript:_e(%7B%7D,'cvml','lshsousa@gmail.com');>>> wrote:

(…) I totally agree with @Vladimir that we could have a more clear and
/swift-ly/ way to concisely wrap those operations.

The behaviour pointed out by him looks very nice and doable to me.

a = [1,2,3]
a[-1..<6] - raises runtime error (right behavior by default, doesn't
affect existing code)
a[truncate: -1..<6] - produces [1,2,3] (the very behaviour I proposed
initially)
a[safe: -1..<6] - produces nil (i.e [T]?) (no runtime errors and makes
it
easy to handle unexpected results)

I don't feel strongly about this. Yes, if this were shorter to express,
it
would feel like /nicer/ design. But what Haravikk and Chris L. already
said
seems to me as /wiser/ design.

IMO it is not just nicer, it provides you with handy and explicit
alternatives.

In some situations, you are checking bounds and you sure that if you
calculated them incorrectly - error will be raised.
But sometimes, you don't need to check exact bounds, probably "take these
values, or give me nil of no such".

I can compare this with Dictionary we have in Swift.
Can you say if it is "wise" to return Optional(T) when we calls
dict[somekey] ? Probably it is wise to raise error if there is no such key?
(to force us to check the key first).

The proposed subscript for special situations when you know you need
exactly this behavior to make your code clear and readable and you fully
controls code&error flow.

(@Vladimir: Besides, I'm sure `.clamped(to:)` wasn't invented for this
purpose but for doing interval arithmetic on ranges. It just happens to
somewhat work here.)

– Would this feature really provide a measurable benefit to developers?
– Under which circumstances do you find yourself with a past-the-end
upper
bound such as 6 where `a.count == 3`?
– …Let alone a /negative/ start index like `-1`?

I find cases like these to be much more common in languages like Python
and
Ruby where e.g. `array[-2]` refers to the penultimate element. Swift
doesn't seem to want to go there.

Each good feature will provide benefit to developers. For those, who work
a lot with arrays/bounds/slices/copies this will provide measurable
benefit, IMO.
Can we live without such improvement? Absolutely. Are there more
important proposals? Yes. But will this make Swift more elegant, handy,
clear? Yes, I believe.

As for "Under which circumstances.." questions. Well.. something like
"get +- 5 elements(at max) with center in some index"

let a = [1,2,3,4,5,6]
let index = random(0..<a.count)
let result = a[truncate: index-5...index+5]

or "get 5 elements from index, if no 5 elements from index - return empty
array"

let a = [1,2,3,4,5,6]
let index = random(0..<a.count)
if let result = a[safe: index..<index+5] //[Int]?
{return result}
else
{return []}

Something like this.

For the use cases I can think of, Swift 3—as the proposal currently goes

<
https://github.com/apple/swift/blob/swift-3-indexing-model/stdlib/public/core/Collection.swift#L724-L808
>—already
offers the following suitable methods:

     array[bounds]
     array.prefix(maxLength)// no precondition
     array.prefix(upTo: index)
     array.prefix(through: index)
     array.dropLast(n)// no precondition
     array.dropFirst(n)// no precondition
     array.suffix(from: index)
     array.suffix(maxLength) // no precondition

If these feel too clumsy to use, maybe we should focus on making them all
more convenient. Ideally, that suggestion would apply to all
`Collection`s.

— Pyry

Yes, some variants can be covered by these methods:
array.prefix(maxLength) -> array[truncate: 0..<maxLength]
array.prefix(upTo) -> array[0..<upTo]
array.prefix(through) -> array[0...through]

And some has no good alternatives in subscription:
array.suffix(from: index) -> array[truncate: index...Int.max ??
array.suffix(maxLength) -> array[truncate: hm..

But. As array[bound] returns a copy(slice) of array, it feels natural to
have variants of behavior of array[bound], just like you have different
variants of prefix() methods.

So it seems for me like this proposal for subscript variants(safe: &
truncate:) is good addition to then proposal you pointed to.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
<javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Obrigado.
Daniel Quirino


(Vladimir) #18

As I understand, currently Range <start> can not be greater than <end>. So we just can't use 0..<-2. And I don't think we should implement such thing as it is not very explicit about what we are expecting.

···

On 14.04.2016 0:29, Dave Abrahams via swift-evolution wrote:

That approach makes sense too. But then do we add

   x[python: 0..<-2] // all but the last two elements?

;^)


(Luis Henrique Borges) #19

I've just updated the proposal draft adding this new approach as an
"alternative considered", hope it conforms to what we've discussed so far:

https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md#alternatives-considered

I'll wait for more feedback so that I can see whether or not I should
submit this proposal for review.

If you have something to add/fix there, please let me know or just send a
pull request :slight_smile:

(ah, sorry for the wrong subject, it should be "[Draft]" instead)

- Luis

···

On Wed, Apr 13, 2016 at 1:50 PM, Vladimir.S via swift-evolution < swift-evolution@swift.org> wrote:

The problem the "a[i &..< j]" is trying to solve is to allow us to work
with array bounds without errors, even if i/j is incorrect, when we
explicitly allows this.

As for your question, yes, it seems like there is a problem :slight_smile:
"i &..< j" should become a new Range. But such range knows nothing about
array and its bounds. Probably such operator is not the best idea.

It seems I'd prefer in this case some kind of a[truncate: -1..<6] and
probably a[safe: -1..<6] - which returns nil if range is incorrect.
So, in this case we'll have these methods and behavior:
a=[1,2,3]
a[-1..<6] - raises runtime error
a[truncate: -1..<6] - produces [1,2,3]
a[safe: -1..<6] - produces nil (i.e [T]?)

Seems like very handy and explicit. Right behavior by default(raises
error). Opinions?

On 13.04.2016 13:52, Maximilian Hünenberger via swift-evolution wrote:

Should this new operator form a new range? How can this range know about
the array's indices?

A while ago there was a proposal (unfortunately it was not discussed
enough) which introduced safe array indexing:

          array[safe: 3] // returns nil if index out of bounds

So another way to handle this issue would be to make another subscript
like:

          array[truncate: -1...6]

Best regards
- Maximilian

Am 12.04.2016 um 01:21 schrieb Luis Henrique B. Sousa via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

The idea of having a new operator following the principles of overflow

operators looks great. Two distinct operators doing implicit and
explicitly might really be a good way to go; it would be concise and
wouldn't look like some magic happened behind the scenes. I'd like to
hear more opinions about it.

> what we'll have in case a[-1 &..< 5]? should this raise error or become
[0 ..< 3] ? I think, the latter.
I agree here, I'd choose the latter.

From my perspective, the behaviour I'm proposing is what a considerable
number of users expect, especially if coming from other languages that
follow that path. Of course I'm not comparing languages here, but
considering the Swift principles of being a safer language, in my opinion
we'd rather have a partial slice than a crash in execution time (when the
user is not totally aware of it).

Many thanks for all your additions so far. It's really good to see that
these things are not set in stone yet.

- Luis

On Apr 11, 2016 4:21 PM, "Vladimir.S via swift-evolution" >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

    +1 for the idea "in general". But I also think that explicit is
    better than implicit, especially if we deal with possible errors.
    Just like we work in Swift with integer overflow : '+' will generate
    run time error, but saying &+ we point Swift that we know what we do.

    but.. what we'll have in case a[-1 &..< 5]? should this raise error
    or become [0 ..< 3] ? I think, the latter.

    On 11.04.2016 17:02, Haravikk via swift-evolution wrote:

        I like the idea in theory, but the question is; is it really
safer to
        return a result that the developer may not have wanted, versus an
        error
        indicating that a mistake may have been made? I wonder if perhaps
        there
        could be an alternative, such as a variation of the operator
like so:

        let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5,
        a.endIndex)],
        becomes let b = a[0 ..< 3]

        I’m just not sure that we can assume that an array index out of
        range error
        is okay without some kind of indication from the developer, as
        otherwise we
        could end up returning a partial slice, which could end up
        causing an error
        elsewhere where the size of the slice is assumed to be 5 but
isn’t.

            On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa via
            swift-evolution
            <swift-evolution@swift.org <mailto:swift-evolution@swift.org
>
            <mailto:swift-evolution@swift.org

            <mailto:swift-evolution@swift.org>>> wrote:

            This proposal seeks to provide a safer ..< (aka half-open
            range operator)
            in order to avoid **Array index out of range** errors in
            execution time.

            Here is my first draft for this proposal:

https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md

            In short, doing that in Swift causes a runtime error:

            leta =[1,2,3]
            letb =a[0..<5]
            print(b)

            > Error running code:
            > fatal error: Array index out of range

            The proposed solution is to slice the array returning all
            elements that
            are below the half-open operator, even though the number of
            elements is
            lesser than the ending of the half-open operator. So the
            example above
            would return [1,2,3].
            We can see this very behaviour in other languages, such as
            Python and
            Ruby as shown in the proposal draft.

            This would eliminate the need for verifications on the array
            size before
            slicing it -- and consequently runtime errors in cases when
the
            programmer didn't.

            Viewing that it is my very first proposal, any feedback will
            be helpful.

            Thanks!

            Luis Henrique Borges
            @luishborges
            _______________________________________________
            swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org>
            <mailto:swift-evolution@swift.org
            <mailto:swift-evolution@swift.org>>
            https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

_______________________________________________

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


(Luis Henrique Borges) #20

is this syntax reasonably simple to implement? Or is there another solution
that would work with less impact in terms of design?
I mean the subscript with a label on it, i.e. collection[label:
Range<Index>]

It's been a while since the last feedback, so I'm doing some rewriting on
this proposal and still considering to submit it for review.

- Luis

···

On Wed, Apr 13, 2016 at 10:29 PM, Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Wed Apr 13 2016, Maximilian Hünenberger <swift-evolution@swift.org> > wrote:

> Should this new operator form a new range? How can this range know about
the
> array's indices?
>
> A while ago there was a proposal (unfortunately it was not discussed
enough)
> which introduced safe array indexing:
>
> array[safe: 3] // returns nil if index out of bounds

Wrong label, but I wouldn't be opposed to adding such an operator for
all Collections.

> So another way to handle this issue would be to make another subscript
like:
>
> array[truncate: -1...6]

That approach makes sense too. But then do we add

  x[python: 0..<-2] // all but the last two elements?

;^)

> Best regards
> - Maximilian
>
> Am 12.04.2016 um 01:21 schrieb Luis Henrique B. Sousa via swift-evolution > > <swift-evolution@swift.org>:
>
> The idea of having a new operator following the principles of
overflow
> operators looks great. Two distinct operators doing implicit and
explicitly
> might really be a good way to go; it would be concise and wouldn't
look like
> some magic happened behind the scenes. I'd like to hear more
opinions about
> it.
>
> > what we'll have in case a[-1 &..< 5]? should this raise error or
become [0
> ..< 3] ? I think, the latter.
> I agree here, I'd choose the latter.
>
> From my perspective, the behaviour I'm proposing is what a
considerable
> number of users expect, especially if coming from other languages
that
> follow that path. Of course I'm not comparing languages here, but
> considering the Swift principles of being a safer language, in my
opinion
> we'd rather have a partial slice than a crash in execution time
(when the
> user is not totally aware of it).
>
> Many thanks for all your additions so far. It's really good to see
that
> these things are not set in stone yet.
>
> - Luis
>
> On Apr 11, 2016 4:21 PM, "Vladimir.S via swift-evolution" > > <swift-evolution@swift.org> wrote:
>
> +1 for the idea "in general". But I also think that explicit is
better than
> implicit, especially if we deal with possible errors. Just like
we work
> in Swift with integer overflow : '+' will generate run time
error, but
> saying &+ we point Swift that we know what we do.
>
> but.. what we'll have in case a[-1 &..< 5]? should this raise
error or
> become [0 ..< 3] ? I think, the latter.
>
> On 11.04.2016 17:02, Haravikk via swift-evolution wrote:
>
> I like the idea in theory, but the question is; is it really
safer to
> return a result that the developer may not have wanted,
versus an
> error
> indicating that a mistake may have been made? I wonder if
perhaps
> there
> could be an alternative, such as a variation of the operator
like
> so:
>
> let b = a [0 &..< 5]// Equivalent to let b = a[0 ..< min(5,
> a.endIndex)],
> becomes let b = a[0 ..< 3]
>
> I’m just not sure that we can assume that an array index out
of
> range error
> is okay without some kind of indication from the developer,
as
> otherwise we
> could end up returning a partial slice, which could end up
causing
> an error
> elsewhere where the size of the slice is assumed to be 5 but
isn’t.
>
> On 11 Apr 2016, at 13:23, Luis Henrique B. Sousa
via
> swift-evolution
> <swift-evolution@swift.org
> <mailto:swift-evolution@swift.org>>
> wrote:
>
> This proposal seeks to provide a safer ..< (aka
half-open range
> operator)
> in order to avoid **Array index out of range** errors in
> execution time.
>
> Here is my first draft for this proposal:
>
https://github.com/luish/swift-evolution/blob/half-open-range-operator/proposals/nnnn-safer-half-open-range-operator.md
>
> In short, doing that in Swift causes a runtime error:
>
> leta =[1,2,3]
> letb =a[0..<5]
> print(b)
>
> > Error running code:
> > fatal error: Array index out of range
>
> The proposed solution is to slice the array returning all
> elements that
> are below the half-open operator, even though the number
of
> elements is
> lesser than the ending of the half-open operator. So the
example
> above
> would return [1,2,3].
> We can see this very behaviour in other languages, such
as
> Python and
> Ruby as shown in the proposal draft.
>
> This would eliminate the need for verifications on the
array
> size before
> slicing it -- and consequently runtime errors in cases
when the
> programmer didn't.
>
> Viewing that it is my very first proposal, any feedback
will be
> helpful.
>
> Thanks!
>
> Luis Henrique Borges
> @luishborges
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> <mailto: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
>
> _______________________________________________
> 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
>
> _______________________________________________
> 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