[swift-evolution] Proposal: Add Safe Subquence Access Via subscript For ColloctionType

Dennis Lysenko dennis.s.lysenko at gmail.com
Mon Dec 14 17:41:23 CST 2015


Sorry, looks like I conflated a few different terms in that message. Just
pretend I said "optional" anywhere I said "nullable", and "dictionary"
anywhere I said "hash". Been context switching among Swift, Java, Ruby and
Kotlin all day.

On Mon, Dec 14, 2015 at 6:40 PM Dennis Lysenko <dennis.s.lysenko at gmail.com>
wrote:

> Jordan, I think the inspiration here might come from Ruby. I must admit
> that seeing that `Array.first` returns an optional, but Array#subscript
> raises a runtime error when the index is out of bounds threw me for a loop.
> In Ruby, both Array#first and Array.subscript return an optional.
>
> If one of the original tenets of swift was to provide greater compile-time
> null-safety, which it definitely seems it was given the commendable
> emphasis on optionals being easy to use, then returning an optional would
> be a solid way to go about subscripting. Think of it this way: when I call
> a method with nullable return value, I am forced to deal with the fact that
> the method can fail at compile time. When I subscript an array, I am not
> forced to deal with it at compile time, and it will fail at runtime instead.
>
> Nullable subscripting is a big departure from the way most modern
> languages do things and that is why I don't blame you for rejecting it.
> That said, it is a pleasant change in the way you think about subscripting.
>
> As a closing thought, subscripting hashes returns an optional value. You
> might consider this a pretty big inconsistency with arrays. Let me flip
> your argument against optional array subscripting, for dictionaries: *When
> you are performing a subscript where the key is out of the key set, is it
> not a programmer error?*
>
> On Mon, Dec 14, 2015 at 4:54 PM Jordan Rose via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> Hi, Daniel. Thanks for bringing this up. May I ask where you would use a
>> "safe" subscript? When are you performing a subscript where the bounds
>> being…um, out-of-bound…is not a programmer error?
>>
>> As for the second half of this, we deliberately decided to not make the
>> subscript operator "smart" (handling negative indexes and such) because
>> extra branches can do very bad things to performance, and because allowing
>> negative indexes sometimes hide bugs. It's also not meaningful for
>> collections whose indexes are not integers.
>>
>> Best,
>> Jordan
>>
>> > On Dec 14, 2015, at 12:52, Daniel Duan via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> >
>> >
>> > In CollectionType, a `Range` is accepted as the argument in a version
>> of `subscript`, which returns a subsequence.
>> >
>> >    [1,2,3,4][2...3] // [3, 4]
>> >
>> > `subscript` raises a fatal error if the range is out of bound, which is
>> really a side-effect from accessing an element with an out of bound index.
>> This behavior forces users to check bounds beforehand. It has been serving
>> us well.
>> >
>> > I propose adding a new interface where user can recover from/defer out
>> of bound error in this context. Here are two potential approaches.
>> >
>> > Approach #1 is more conservative, we add a throwing version of
>> `subscript`. It throws an error if the range is out of bound. We can give
>> the range parameter a name for distinction, resulting usage would look like:
>> >
>> >    do {
>> >       let gimme = [1,2,3,4][safe: 2...4]
>> >    } catch {
>> >        recover()
>> >    }
>> >
>> > As an alternative, we can replace the original `subscript` with this
>> version, breaking backward compatibilty.
>> >
>> > Apporoach #2 is a really sweet syntax sugar. We add a new subscript
>> that accepts 2 arugments:
>> >
>> >    extension CollectionType where Self.Index: RandomAccessIndexType {
>> >        public subscript(start:Int?, end:Int?) -> Self.SubSequence { ...
>> }
>> >    }
>> >
>> > This version would make ANY combination of arugment safe by enabling a
>> sematic similar to Python's slicing mechanism. Explanations come after
>> these examples:
>> >
>> >    [0,1,2,3][1, -1]                    // [1, 2]
>> >    ["H","e","l","l","o"][-1000, nil]   // ["H","e","l","l","o"]
>> >    [1,2,3,4,5,6,7,8][1,5][2,3]         // [4]
>> >
>> > This should look familiar to Python users:
>> >
>> > * the access is always clamped in-bound. Interpret out-of-bound number
>> as the boundary.  [1,2,3][0: 100] means [1,2,3][0: 2].
>> > * nil indicate the boundary itself. [1,2,3][0: nil] means [1,2,3][0: 2]
>> > * negative index counts from the end of the sequence. [1,2,3][-2, -1]
>> means [1,2,3][(3-2), (3-1)]
>> >
>> > Admittedly, this syntax suger seems a little out-of-place in Swift :P
>> >
>> > Both approaches require just a little of work. As an example, here's
>> one implementation of the 2nd:
>> https://github.com/dduan/Lic/blob/master/Lic/Lic.swift (please ignore
>> the extension for String, that'd be in a separate proposal, if any).
>> >
>> >
>> > What do you think?
>> >
>> > - Daniel Duan
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> _______________________________________________
>> 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/20151214/8968e6f8/attachment.html>


More information about the swift-evolution mailing list