Safe Random Access Collection Element

This is a good idea! Because you haven't written down the signature of the function you propose, it's a bit difficult to know exactly what you want here. I can conceive of two signatures:

extension RandomAccessCollection {
    subscript(safe: Index) -> Optional<Element>

    subscript(safe: Int) -> Optional<Element>
}

These are slightly different in semantics. The first is a straightforward wrapper around the basic Index operation that performs a bounds-check before accessing the element. The second is a more complex beast that moves forward into offset-based indexing.

I think we should restrict this discussion to the former. The latter is part of a wider discussion around SE-0256 (see [Returned for revision] SE-0265: Offset-Based Access to Indices, Elements, and Slices for more).

The former is an extremely straightforward method. It's simple, does not currently exist, and simplifies some reasonably common code for accessing collections at arbitrary indices. If it were not for the fact that it operates on Index I'd say it's a slam-dunk.

However, it's slightly less useful than it seems on most collections though. There are very few collections that behave like Array, where they are both a) Index == Int and b) startIndex == 0: that is, where they are indexed by an integer type and zero-indexed. The Swift Standard Library contains only one such Collection: Array itself. Other major Swift libraries often also don't contain such Collections: SwiftNIO doesn't either, for example.

For collections that have either got non-integer indices or whose startIndex may not be 0, it is much less common to directly index them with an Index that may not be in the Collection. Usually you need to actually create an Index, and most of the ways of doing so guarantee that the Index is valid for the collection. For example, things like firstIndex(of:) and firstIndex(where:) will only return valid indices for the Collection.

More or less the only thing I can think of that would do this is calling index(after:), which may produce endIndex, which cannot safely subscript the Collection. In this case there's some mild utility, but if you were doing that you're almost always doing so in a loop. Not always (indeed, I just recently reviewed some code that did exactly this outside a loop, and where we saw runtime crashes), so there's definitely some utility still there, but I don't think it's terribly common.

All-in-all, I remain kinda neutral on this proposal. I don't think it detracts from the language, but I don't think it adds huge value for most Collections aside from Array. That raises the question of whether we should either a) just define this for Array, or b) try to get SE-0256 moving forward again instead. I don't have a strong view either way, but I think those are the other options on the table here.

3 Likes