> 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
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to