Subscripting a Range seems unintuitive

(George) #1

The following is confusing to me, and possibly a bug:

print((0..<4)[2]) // 2
print((4..<8)[2]) // Index out of range

Worse, print(Array(4..<8)[2]) results in the expected 6

This is an issue because I'm using range[range.count/2] to get middle of a range.

1 Like
Pitch: Offsetting Indices and Relative Ranges
String Essentials
#2

It’s not a bug.
The indices of a range is the range itself, while the indices of an array is 0..<count.

So

4..<8
Index : 4, 5, 6, 7
Value : 4, 5, 6, 7

Array(4..<8)
Index : 0, 1, 2, 3
Value : 4, 5, 6, 7
2 Likes
(Jeremy David Giesbrecht) #3

In general, indices are never offsets, and they may not be even remotely integer‐like.

print(["a", "b", "c"].startIndex) // 0
print(["a", "b", "c"].dropFirst().startIndex) // 1
print("Hello, world!".startIndex) // [gibberish]
print([1: "I", 2: "II", 3: "III"].startIndex) // [gibberish]

Try to think in terms of abstract collections and implement your algorithms that way. In the generic setting, the difference between Index and IndexDistance is enforced by the type checker:

extension Collection {
    var middleElement: Element {
        let middleIndex = self.index(self.startIndex, offsetBy: self.count / 2)
        return self[middleIndex]
    }
}

print((4 ..< 8).middleElement) // 6
5 Likes