[swift-evolution] [Review] SE-0172: One-sided Ranges

David Waite david at alkaline-solutions.com
Tue Apr 18 05:19:35 CDT 2017

> On Apr 17, 2017, at 10:40 PM, Douglas Gregor via swift-evolution <swift-evolution at swift.org> wrote:
> https://github.com/apple/swift-evolution/blob/master/proposals/0172-one-sided-ranges.md <https://github.com/apple/swift-evolution/blob/master/proposals/0172-one-sided-ranges.md>
> What is your evaluation of the proposal?
I really like the syntax and functionality. I especially like that it creates a protocol that all the various range types implement.

Comments of varying quality:

1. The following example at the start of the proposal does not compile, due both to index(where:) being inappropriate (I assume index(of:) was wanted?) , and index(where:)  returning an optional:
let s = "Hello, World!"
let i = s.index(where: ",")
let greeting = s[s.startIndex..<i]

I assume representing an optional as an input to a one-sided range is not intended - it would add complexity and likely mandate an AnyRangeExpression<T> type-erasing class. It is also more likely desirable for greeting to be nil in this case, rather than being an empty String.

It is probably appropriate instead to change the example. To avoid conditionals, I usually go with this syntax:

let s = "Hello, World!"
let i = s.index(where: ",")
let greeting = i.map { s[s.startIndex..<$0] }

2. More on topic, RangeExpression is a protocol that all ranges implement, but appears to only be defined to be evaluated in the context of a collection and its collection indexes. Are there any other non-collection uses of this, such as intersecting two ranges (see point 5)?

3. As more of a general concern about Indexes and Comparable - RangeExpression has a `contains` method, raised I assume from the existing Range types and based on the Comparable index.

However, is it appropriate to evaluate collection indexes in this way, isolated from the collection itself? Today,types like DictionaryIndex will give arbitrary comparison results for indexes generated from two different dictionaries, but trap when methods like distance(from:to:) are called. This may be a bug in the case of DictionaryIndex, but it is not expected that indexes contain information about the collection they came from (such as Array, indexed by Int)

To ask as a more direct question: is it appropriate that an index may return true from RangeExpression contains, but causes a fatal error when used against the collection the RangeExpression index(es) came from?

4. As an extension to the third point, there appears to be a larger API surface of the Range types which could be exposed, such as overlaps() and clamped(to:). If contains() is appropriate for RangeExpression, would it make sense to include these, as well as possibly changing them to be expressed with RangeExpression arguemnts?

5. As a second extension to the third point, some languages have “creative” ranges which only make sense in the context of a collection. An example would be (from Ruby):

“Hello, World!”[-5...-1] # “World"

where the negative index indicates an a negative distance from the end index.

Ignoring syntax bike shedding for the moment, such an expression could not be represented as a RangeExpression due to the inability to properly implement ‘contains’ in isolation of the collection to resolve proper indexes from these offsets.

There would still be ways to implement such behavior if desired by not having the type be a proper RangeExpression and extending Collection. The question is just meant to be another questioning of the relationship of RangeExpression to standalone ranges and to collections.

6. The proposal states:

The prefix and suffix methods that take an index are currently protocol requirements, but should not be. This proposal will fix that as a side-effect.
prefix and suffix will be deprecated in Swift 4 and later removed.

It seems removal of prefix and suffix methods from the Collection protocol is a breaking change in addition to removing prefix/suffix from Collection. 

Would it be perhaps more desirable for Swift 4 to make prefix/suffix defined on an extension as well as deprecating them for removal in a later version of Swift? This could be done independent of whether this proposal is fully implemented/ships within Swift 4.

> Is the problem being addressed significant enough to warrant a change to Swift?
> Does this proposal fit well with the feel and direction of Swift?
I think so. It will both create a more powerful collection indexing syntax and eliminate multiple functions on collection in the future. The syntax as well I believe is a good fit for the language.

> If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
I’ve used ranged subscripts in ruby, and to a lesser degree python. Ruby in particular has more in-line functionality for expressing complex subsequence operations (such as negative integer indexes representing a negative offset from the endIndex). 

One fun part is that if RangeExpression is an exposed protocol, third parties can implement such extended functionality independent of the standard library (possibly included later if it works out to be highly used with a clear syntax winner.)

> How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
In-depth study


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170418/bbc34974/attachment.html>

More information about the swift-evolution mailing list