[Draft] Adding Safe indexing to Array

Proposal has been archived.

11 Likes

I love the idea, and would actually prefer if standard subscripting behavior were more like this.

However, I don't like the conflation of nil that will occur when the array holds optionals.

I've gotten around that like this. I'd prefer a subscript but they can't throw errors:

public extension Array {
  struct OutOfBoundsError: Error {
    public let index: Index
  }
  
  /// - Returns: same as subscript, if index is in bounds
  /// - Throws: Array.OutOfBoundsError
  func getElement(index: Index) throws -> Element {
    guard indices.contains(index)
    else {throw OutOfBoundsError(index: index)}
    
    return self[index]
  }
}

This is officially out of bounds for standard subscripting because of the performance hit among other reasons.

I don't think having to double-unwrap for optionals is any more an issue than if a dict stores optional values.

Erica, I do believe the core team weighed in earlier to say that this subscript should not be called "safe," which in Swift refers specifically to memory safety. The suggested term, if I recall, was "lenient" or "checked."

2 Likes

I have safe on Collection in my code base and use it help a lot.
Your proposition will be a great addition to the standard library.

1 Like

I didn't see that but that's a great catch. Happy to revise it to checked (which I prefer to lenient)

Some will reply that a[i] is already checked, and that a[checked: i] is redundant.

"Lenient" is hard to read for non-native English speakers that have a limited vocabulary (and code readability is important).

a[safe: i] matches what's is everyone's mind (avoid crash), but does not match "safe" as Swift likes to define it (comply to preconditions or crash).

It could live with short and purely made-up subscripts, like a[at: i], or a[index: i]. We'd all get used to them, since it's quite a frequent use case.

1 Like

"Lenient" was the top agreed-upon choice, if I recall. It's fine if non-native speakers don't know the word; they can look it up. If it's hard to look up (like an idiomatic expression), then it can be deeply unfair to non-native speakers, but that's not the case here.

We can always bikeshed other options. ifExists: would be unambiguous, for example.

a[valid: i]
a[existing: i]

1 Like

Agreed on the "more of an issue". If you don't already take issue with multi-optionals, we won't see eye-to-eye.

My major issue with this pitch is that it uses a subscript instead of a function like element(at:) because the discoverability of subscript overloads is quite difficult already (at least Xcode does not provide any autocompletion for subscript labels). But this addition of a checked access to elements is more than welcome.

Those read to me like you're asserting that i is in fact valid or existing, such that if that index is invalid we'd have a precondition failure.

Adding function to alternatives. Thank you

1 Like

Kind of agree, but wouldn't that be true about eg a[safe: i] too?

Yup. Hence, something like ifExists: (which explicitly disavows knowledge of whether i exists or not at the call site).

2 Likes

I am curious what situations you encounter where this is useful. Personally, I find it far more common to obtain an optional index—such as from index(where:)—and want to subscript with it if valid.

Perhaps both scenarios can be handled with one solution:

subscript(optional idx: Index?) -> Element? {
  if let i = idx, indices.contains(i) { return self[i] }
  return nil
}
2 Likes

FWIW, Swift uses "safe" to refer to the Optional type several times on its about page: Swift.org - About Swift

4 Likes

Just one question: why on Array and not on Collection?

1 Like

IIRC, checking whether an index is valid for any arbitrary Collection is O(n). Array (and RandomAccessCollection?) can do this in O(1).

Sure it does; Optional is one tool that provides memory safety. The point is not that the proposed method is unsafe--of course it's safe. The point is that the label is supposed to distinguish this subscript from the unlabeled subscript. However, the unlabeled subscript is also safe, and it's a common misconception that it's not--a misconception we're trying not to perpetuate.

1 Like