[swift-evolution] Strings in Swift 4

Xiaodi Wu xiaodi.wu at gmail.com
Wed Feb 1 09:09:41 CST 2017


Brent--

In general, I agree with the direction of your thinking. Time constraints
prevent me from responding as thoroughly as I'd like, but briefly, where we
don't agree at the moment boil down to a few points:

* Agree that "to" vs "through" is not ideal. However, having spent a lot of
time on this issue, I'm quite convinced there is no single word in English
that will accurately describe the distinction. Certainly, we can mimic the
English language by doing something like `stride(from: a, to: b,
.exclusive, by: c)`. However, one other solution to provide clarity is to
pick a convention and solidify user understanding by frequent and
consistent use, which is the diametric opposite of your stance that we
shouldn't use the convention elsewhere.

In general, I think we contort ourselves in the wrong way when the first
listed motivation for a new feature is to work around a naming difficulty:
the solution to not having found the right name is to find the right name.

* It is not redundant API simply because the same thing can be achieved by
composing two other functions. One must assess ergonomics, footgun
likelihood, etc. But in any case, the point you make here is equally
applicable to your proposed feature, i.e. arr[0...][..<2] == arr[0..<2].

* I fully expect subscript labels to start making an appearance in stdlib
APIs sooner or later. I don't think its absence is indicative of a
conscious rejection of them, just that they haven't been needed. (Lenient
subscripts will one day make an appearance, given how often it's requested,
and I sure hope they are labeled.)

* Disagree that the labeled subscript is ad-hoc. In the contrary, I think
"incomplete ranges" are the more ad-hoc choice for array subscripting. My
point is that an "incomplete range" is, by definition, not a range; it is a
bound, which is an Index. We don't need a wrapper around the Index in the
form of IncompleteRange<Index> because it provides little if any semantic
value: the bounds of such a range are not knowable divorced from the
sequence being indexed, and so the upperboundedness or lowerboundedness of
IncompleteRange<Index> is not a useful piece of information without the
sequence. Thus, it is more appropriately a label when you invoke a
subscript on a sequence, not a property of the argument, which is a bound.

* Removing one of the bounds _is_ a natural impulse, but the natural result
one would expect to get is a half-unbounded range (i.e. infinite range),
not an "incomplete range." As I argued above, one must distinguish these
semantics. You are proposing something with the semantics of an "incomplete
range."

* Your example of switch statements is (a) mostly sugar (the exhaustiveness
checking made possible could also be proposed independent of syntax
changes); and (b) arguably an infinite range in semantics. I'll have to
think more on this, though.

Bottom line, I can support an infinite range, but I don't think I like the
idea of an "incomplete range." An "incomplete range" is an Index used as a
lower or upper bound and should be expressed as a plain Index, because it
is not a range. An infinite range, OTOH, is a range. However, the array
subscripting use case is not a use case for infinite ranges, as I've argued
above.
On Wed, Feb 1, 2017 at 08:29 Matthew Johnson <matthew at anandabits.com> wrote:

>
> > On Feb 1, 2017, at 6:58 AM, Brent Royal-Gordon via swift-evolution <
> swift-evolution at swift.org> wrote:
> >
> >> On Jan 31, 2017, at 2:04 PM, Xiaodi Wu via swift-evolution <
> swift-evolution at swift.org> 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.
>
> +1 in general.  But I’m still curious how postfix `…` would impact our
> options for variadic generics and tuple unpacking in the future.
>
> >
> > --
> > Brent Royal-Gordon
> > Architechies
> >
> > _______________________________________________
> > 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/20170201/c2829646/attachment.html>


More information about the swift-evolution mailing list