4

When accessing a dictionary, such as [String: Any], the result type is Optional(Any).

When indexing an array of [Any], the result type is Any, and the call can throw a fatal error.

Is there any reason for this difference?

It would be so nice to branch execution with a guard let, if let, ?, and ??, but instead you have to wrap array indexing in an if data.count <= index.

10
  • 1
    the call can throw an IndexError.. No, it cannot throw, it raises an exception. An out-of-range exception cannot be caught with try - catch. Commented Jan 31, 2020 at 18:56
  • 1
    Most likely the reason is the Objective-C compatibility. Commented Jan 31, 2020 at 19:03
  • 1
    Compare Safe (bounds-checked) array lookup in Swift, through optional bindings?. Commented Jan 31, 2020 at 19:06
  • 1
    @JoakimDanielson But it does have a "well defined set" (a range is just particular kind of set, with contiguous members), so I think that's a moot point. Commented Jan 31, 2020 at 19:13
  • 1
    @RolfLocher: Theoretically yes: You can define a subscript (index: Index) -> Element? method, but then you have to call it as let b: Int? = a[0] or let b = a[0] as Int? so that the compiler can distinguish the methods from the context. I would not recommend that. – Actually I would not use a “safe subscript” at all. As said above, you always know which indices are valid. A failure might indicate a logic error in your code. Commented Jan 31, 2020 at 19:16

1 Answer 1

8

It's ultimately for performance reasons:

Commonly Rejected Changes

...

Strings, Characters, and Collection Types

  • Make Array<T> subscript access return T? or T! instead of T: The current array behavior is intentional, as it accurately reflects the fact that out-of-bounds array access is a logic error. Changing the current behavior would slow Array accesses to an unacceptable degree. This topic has come up multiple times before but is very unlikely to be accepted.

https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md#strings-characters-and-collection-types

Though nothing stops you from rolling your own:

extension Collection {
    subscript(safelyIndex i: Index) -> Element? {
        get {
            guard self.indices.contains(i) else { return nil }
            return self[i]
        }
    }
}

let array = Array(0...10)
let n = array[safelyIndex: 3]
print(n as Any) // => Optional(3)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.