[swift-evolution] Strings in Swift 4

Xiaodi Wu xiaodi.wu at gmail.com
Tue Jan 31 18:32:08 CST 2017


On Tue, Jan 31, 2017 at 6:27 PM, Jaden Geller <jaden.geller at gmail.com>
wrote:

>
> On Jan 31, 2017, at 4:20 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Tue, Jan 31, 2017 at 6:15 PM, Jaden Geller <jaden.geller at gmail.com>
> wrote:
>
>>
>> On Jan 31, 2017, at 4:09 PM, Matthew Johnson via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>
>> On Jan 31, 2017, at 5:35 PM, Xiaodi Wu via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> On Tue, Jan 31, 2017 at 5:28 PM, David Sweeris <davesweeris at mac.com>
>> wrote:
>>
>>>
>>> On Jan 31, 2017, at 2:04 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>
>>> On Tue, Jan 31, 2017 at 3:36 PM, David Sweeris via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>>
>>>> On Jan 31, 2017, at 11:32, Jaden Geller via swift-evolution <
>>>> swift-evolution at swift.org> wrote:
>>>>
>>>> I think that is perfectly reasonable, but then it seems weird to be
>>>> able to iterate over it (with no upper bound) independently of a
>>>> collection). It would surprise me if
>>>> ```
>>>> for x in arr[arr.startIndex…] { print(x) }
>>>> ```
>>>> yielded different results than
>>>> ```
>>>> for i in arr.startIndex… { print(arr[i]) } // CRASH
>>>> ```
>>>> which it does under this model.
>>>>
>>>>
>>>> (I *think* this how it works... semantically, anyway) Since the upper
>>>> bound isn't specified, it's inferred from the context.
>>>>
>>>> In the first case, the context is as an index into an array, so the
>>>> upper bound is inferred to be the last valid index.
>>>>
>>>> In the second case, there is no context, so it goes to Int.max. Then,
>>>> *after* the "wrong" context has been established, you try to index an
>>>> array with numbers from the too-large range.
>>>>
>>>> Semantically speaking, they're pretty different operations. Why is it
>>>> surprising that they have different results?
>>>>
>>>
>>> I must say, I was originally rather fond of `0...` as a spelling, but
>>> IMO, Jaden and others have pointed out a real semantic issue.
>>>
>>> A range is, to put it simply, the "stuff" between two end points. A
>>> "range with no upper bound" _has to be_ one that continues forever. The
>>> upper bound _must_ be infinity.
>>>
>>>
>>> Depends… Swift doesn’t allow partial initializations, and neither the
>>> `.endIndex` nor the `.upperBound` properties of a `Range` are optional.
>>> From a strictly syntactic PoV, a "Range without an upperBound” can’t exist
>>> without getting into undefined behavior territory.
>>>
>>> Plus, mathematically speaking, an infinite range would be written "[x,
>>> ∞)", with an open upper bracket. If you write “[x, ∞]”, with a *closed* upper
>>> bracket, that’s kind of a meaningless statement. I would argue that if
>>> we’re going to represent that “infinite” range, the closest Swift spelling
>>> would be “x..<“. That leaves the mathematically undefined notation of “[x,
>>> ∞]”, spelled as "x…” in Swift, free to let us have “x…” or “…x” (which by
>>> similar reasoning can’t mean "(∞, x]”) return one of these:
>>>
>>> enum IncompleteRange<T> {
>>>     case upperValue(T)
>>>     case lowerValue(T)
>>> }
>>>
>>> which we could then pass to the subscript function of a collection to
>>> create the actual Range like this:
>>>
>>> extension Collection {
>>>     subscript(_ ir: IncompleteRange<Index>) -> SubSequence {
>>>         switch ir {
>>>         case .lowerValue(let lower): return self[lower ..< self.endIndex
>>> ]
>>>         case .upperValue(let upper): returnself[self.startIndex ..<
>>> upper]
>>>         }
>>>     }
>>> }
>>>
>>>
>> I understand that you can do this from a technical perspective. But I'm
>> arguing it's devoid of semantics.  That is, it's a spelling to dress up a
>> number.
>>
>>
>> It’s not any more devoid of semantics than a partially applied function.
>> It is a number or index with added semantics that it provides a lower (or
>> upper) bound on the possible value specified by its type.
>>
>>
>> If we treat it as such, we shouldn’t allow users to iterate over it
>> directly:
>> ```
>> for x in 0… { // <- doesn’t make sense; only partially specified
>>   print(“hi”)
>> }
>> ```
>>
>> We __could__ introduce 2 types, `IncompleteRange` and `InfiniteRange`,
>> providing an overload that constructs each. It would never be ambiguous
>> because `InfiniteRange ` would be the only `Sequence` and `IncompleteRange`
>> would be the only one of these two that is accepted as a collections
>> subscript.
>>
>> This *isn’t* that crazy either. There’s precedent for this too. The `..<`
>> operator used to create both ranges and intervals (though it seems those
>> type have started to merge).
>>
>> ¯\_(ツ)_/¯
>>
>
>
> Mercifully, those types have completely merged AFAIK. IMO, the long-term
> aim should be to have ... and ..< produce only one kind of range.
>
>
> There are still 2 variants (`Range` and `CountableRange`), but I imagine
> conditional conformances will combine those entirely.
>

Per Dave, that's the goal :)

(I hope conditional conformances are still in scope for Swift 4. They seem
> to have a very significant ABI impact.)
>
>
> What is such an `IncompleteRange<T>` other than a value of type T? It's
>> not an upper bound or lower bound of anything until it's used to index a
>> collection. Why have a new type (IncompleteRange<T>), a new set of
>> operators (prefix and postfix range operators), and these muddied semantics
>> for something that can be written `subscript(upTo upperBound: Index) ->
>> SubSequence { ... }`? _That_ has unmistakable semantics and requires no new
>> syntax.
>>
>>
>> Arguing that it adds too much complexity relative to the value it
>> provides is reasonable.  The value in this use case is mostly syntactic
>> sugar so it’s relatively easy to make the case that it doesn’t cary its
>> weight here.
>>
>> The value in Ben’s use case is a more composable alternative to
>> `enumerated`.  I find this to be a reasonably compelling example of the
>> kind of thing a partial range might enable.
>>
>> I also tend to find concise notation important for clarity as long as it
>> isn’t obscure or idiosyncratic.  With that in mind, I think I lean in favor
>> of `…` so long as we’re confident we won’t regret it if / when we take up
>> variadic generics and / or tuple unpacking.
>>
>>
>>
>> _______________________________________________
>> 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/20170131/47230d76/attachment.html>


More information about the swift-evolution mailing list