Remco Poelstra
Remco Poelstra

Reputation: 985

`IndexSet` is never really empty?

I stumbled across the following behaviour that I didn't expect:

let myIndexSet = IndexSet()
let index = myIndexSet[myIndexSet.startIndex] //index = 0

Doing a similar trick with an Array crashes with an out-of-bounds error as I would expect.

Why does IndexSet allow this? Is this expected behaviour that I can rely on? (It's actually quite useful for my situation)

Upvotes: 2

Views: 175

Answers (1)

Sweeper
Sweeper

Reputation: 272885

This seems like a bug - it directly contradicts the behaviour documented in Collection.

The documentation for Collection.subscript(Index) -> Element says the following about its parameter:

The position of the element to access. position must be a valid index of the collection that is not equal to the endIndex property.

and yet the following prints 0:

let myIndexSet = IndexSet()
print(myIndexSet[myIndexSet.endIndex])

Note that the index set is empty, as indicated by its count as isEmpty properties, and also the fact that its startIndex is equal to its endIndex.

print(myIndexSet.count) // 0
print(myIndexSet.isEmpty) // true
print(myIndexSet.startIndex == myIndexSet.endIndex) // true

Looking at its source code in the swift-corelibs-foundation implementation, we can see exactly why:

public subscript(index : Index) -> Element {
    return index.value
}

It does no checking of whether itself is empty or not. The return value of this subscript depends solely on index! Looking at the blame, this line of code was added 6 years ago and no one changed it or reported this bug since then. I guess "this shouldn't work but it does" is just less easy to find than "this should work but doesn't" :)

I have since posted this bug report.

Upvotes: 2

Related Questions