Why does someData.suffix(2)[0] choke?

I've been away from Swift for a bit, and am doing some app maintenance, and had to rediscover this whole thing about sometimes things that return subcollections that are still subscripted from the original. The code that confused the heck out of me for a bit, reduced to a workspace, was this:

let a = Data(bytes: [10, 20, 30, 40, 50, 60, 70])
let b = a.suffix(2)
b[0] // I expected 60 here, instead I get an exception, an exception that didn't really tell me much

I relearned why I prefer the subdata(in:) method.

The documentation for Data talks about multiple methods that return a subsequence, but nowhere is there a link to that kind of subsequence not being what you'd expect. If Swift wants to be different (surprise the user), fine. What I'm trying to understand is why? And how to better avoid being surprised by this kind of thing in the future?

With Strings, you avoid this, because you have to go through the whole startIndex thing to get at an individual element. But Data elements are directly accessible via Int subscripting.

Unless I'm mistaken, the intended design is that sub-collections always share indices with their original collection. If you have a valid index to an element of a sub-collection, you should be able to use that index to access the same element in the collection even if the index type is opaque (as in String). All first-party types should behave that way and if you encounter any exceptions, I'd file a bug.

In your example:

let a = Data(bytes: [10, 20, 30, 40, 50, 60, 70])
let b = a.suffix(2)
b.startIndex // 5

Therefore, the element at index 0 is out of bounds.

3 Likes

And the reason for this is so that you can do searches and such on sub-collections and get back indexes that will work anywhere.

3 Likes

As a quick mention, b.first will return 60 (as Optional).

1 Like