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

Jordan Rose jordan_rose at apple.com
Mon Dec 14 15:54:31 CST 2015


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



More information about the swift-evolution mailing list