> 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.
However…
> 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
Architechies
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution