> On Jan 31, 2017, at 2:04 PM, Xiaodi Wu via swift-evolution 
> <[email protected]> wrote:
> 
> Therefore I'd conclude that `arr[upTo: i]` is the most consistent spelling. 
> It also yields the sensible result that `arr[from: i][upTo: j] == arr[upTo: 
> j][from: i] == arr[i..<j]`.

There's a lot I dislike about `subscript(upTo/through/from:)`:

1. We have not previously been very satisfied with how understandable these 
labels are—for instance, we fiddled around with them a lot when we were looking 
at `stride(from:to/through:by:)` in Swift 3, and eventually settled on the 
originals because we couldn't find anything better. I don't think entrenching 
them further makes very much sense.

2. The fact that you *can* write `arr[from: i][upTo: j]`, and that this is 
equivalent to both `arr[upTo: j][from: i]` and `arr[i..<j]`, seems a bit weird. 
We aren't typically in the habit of providing redundant APIs like this.

3. Neither Stdlib nor the Apple frameworks currently contain *any* labeled 
subscripts, so this design would be unprecedented in the core language.

4. After a new programmer learns about subscripting with two-sided ranges, 
removing one of the bounds is a straightforward extension of what they already 
know. The argument label solution is more ad-hoc.

5. The argument label solution solves the immediate problem, but doesn't give 
us anything else.

To understand what I mean by #5, consider the implementation. The plan is to 
introduce a `RangeExpression` protocol:

        protocol RangeExpression {
                associatedtype Bound: Comparable
                func relative<C: Collection(to collection: C) where C.Index == 
Bound -> Range<Bound>
        }

And then reduce the many manually-generated variants of `subscript(_: 
Range<Index>)` in `Collection` to just two:

        protocol Collection {
                ...
                subscript(bounds: Range<Index>) -> SubSequence { get }
                ...
        }
        
        extension Collection {
                ...
                subscript<Bounds: RangeExpression>(bounds: Bounds) where 
Bounds.Bound == Index -> SubSequence {
                        return self[bounds.relative(to: self)]
                }
                ...
        }

This design would automatically, source-compatibly, handle several different 
existing types you can slice with:

* ClosedRange
* CountableRange
* CountableClosedRange

Plus the new types associated with incomplete ranges:

* IncompleteRange
* IncompleteClosedRange

Plus anything else we, or users, might want to add. For instance, I have a 
prototype built on `RangeExpression` which lets you write things like:

        myString[.startIndex + 1 ..< .endIndex - 1]

This strikes me as a pretty cool thing that some people might want. 

Similarly, IncompleteRange and IncompleteClosedRange can most likely be put to 
other uses. They could easily fill a gap in `switch` statements, which don't 
have a good way to express open-ended comparisons except with a `where` clause. 
As some have mentioned, when applied to a `Strideable` type they *could* be 
treated as infinite sequences, although it's not clear if we really want to do 
that. And, you know, sometimes you really *do* have a case where one or both 
bounds of a range may be missing in some cases; incomplete ranges are a 
built-in, batteries-included way to model that.

To put it simply, slicing with incomplete ranges gives us several valuable 
tools we can apply to other problems. Labeled subscripts, on the other hand, 
are just another weird little thing that you have to memorize, and probably 
won't.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to