Why is endIndex one greater than the last valid subscript argument, rather than simply the last valid subscript argument? I’m sure there are great reasons for this, but I just can’t think of them myself.
It’s hard to handle empty collections, otherwise. If endIndex were the last valid subscript, then in an empty collection what would its value be? Presumably it would have to point to one before the start, which is rather weird because that’s never a valid index (in an int-indexed collection it would be negative.) Even worse, endIndex is never reachable from startIndex, so an iteration can’t simply continue until it reaches the endIndex. Instead the Indexable type would have to implement a (cheap, constant-time) >= operator to use as the test for an iteration.
These are probably the reasons why C++ also uses the convention of a collection’s end() pointing to one past the end.
I’m implementing a binary tree and I want to implement BidirectionalCollection. Each index contains a (private) reference to the corresponding node in the tree. However, endIndex shouldn’t point to anything, and it makes things very complicated if I want a constant time implementation of index(before:).
Have the tree object keep a pointer to its last node. That makes it cheap to get that node as the ‘before’ of the last node. You’ll also have the benefit of making endIndex() itself constant-time, whereas presumably it’s now O(log n) since you have to walk down the tree to find it.
Or alternatively, you could add a flag to your index type that indicates it’s pointing to the end of the collection. Then the endIndex() really points to the last node but has the flag set.
—Jens
···
On Jul 2, 2016, at 9:48 AM, Tim Vermeulen via swift-users <swift-users@swift.org> wrote: