[swift-evolution] [Review] SE-0065 A New Model for Collections and Indices

Brent Royal-Gordon brent at architechies.com
Wed Apr 13 00:12:26 CDT 2016

> I want to make a point that avoiding precondition violations by
> removing preconditions is not the solution.  When you design an API,
> it frequently has some constraints on the arguments or on the
> execution environment, which, when violated, prevent the API from
> performing the operation correctly.

I totally agree with this section, and I've made similar arguments in the past on this list. For instance, I've been critical in the past of suggestions that failable initializers should be removed, or that all subscripts should be Optional.

> Let's talk about how this applies to Collection.
> For example, Collection APIs in question that work with indices are
> primitive APIs that the rest of Collection APIs build upon.  One of
> these APIs, basically the reason why indices exist, is
> Collection.subscript(Index).  Today the behavior is unspecified if the
> index is not valid.  If we follow the principle that you outlined:
>> not accidentally using an index which would violate the preconditions of the methods or properties you are planning to use it with.
> Collection.subscript(Index) should return an optional.  Does this
> match your expectations?  If so, how do you imagine even trivial
> algorithms written?
> for i in data.indices {
>  data[i]! = data[i]! * 2   // assume that 'data[i]!' can be made settable.
> }

Yes, I totally agree that `Collection.subscript(_: Index)` should not be Optional.

But I think that index-manipulation methods like `successor(of:)` are a different story. It is normal and expected that, when you alter an index, you will occasionally hit the boundaries of the collection. There certainly are cases where you know a particular index manipulation is safe, but most index manipulations need to be guarded by something like:

	while index < collection.endIndex {
		let nextIndex = collection.successor(of: index)
		index = nextIndex

In these cases, it would be better if the `successor(of:)` method was designed in a way that acknowledged and encapsulated the bounds check that is usually required when it is used:

	while let nextIndex = collection.successor(of: index) {
		index = nextIndex

Given the difficulties of statically detecting index invalidation, I totally agree that (as you discussed in a section I've snipped) we can't statically prove indexes are safe. But we can, at the point where we generate an index, easily check if that index is *currently* valid. And it's something that most callers will have to do anyway if we don't do it ourselves.


> I would like to draw attention to the following part:
> // Approach #3: change Collection.index(_:stepsFrom:limitedBy:) to return an
> // optional index.
> //
> // This method has to perform the range check to stop advancing the index when
> // it reaches the limit. Currently it just discards the information about
> // whether it reached the limit or not. Instead, it can cheaply return it to
> // the caller.
> //
> // Note that the same logic does not apply to other
> // Collection.index(_:stepsFrom:) overloads.
> We will change the index(_:stepsFrom:limitedBy:) overload to return an
> optional, and we will see what other implications it has, and how it
> fits into the rest of the system.

I'm glad to hear you'll evaluate this option, and I think it can give us both what we want from this API.

I think having the most high-level operations incorporate bounds checks, while the lower-level ones don't, is a good compromise. If we encourage people to use `index(_:stepsFrom:limitedBy:)` unless they know what they're doing, naïve clients will get an implicit bounds check, while sophisticated, speed-sensitive clients can use methods like `successor(of:)` which require them to check bounds manually.

(There might even be a case for offering bounds-checked `successor(of:limitedBy:)` and `predecessor(of:limitedBy:)` methods to give people bounds-checked alternatives to all three.)

> Thanks again, Brent.

Thank you!

Brent Royal-Gordon

More information about the swift-evolution mailing list