Swift: Safe array indexing: my favorite thing of the new week

teddy-and-rose-1444432-m

// Thanks Mike Ash
extension Array {
    subscript (safe index: UInt) -> Element? {
        return Int(index) < count ? self[Int(index)] : nil
    }
}

You use it as a labeled subscript, e.g. myArray[safe:3]. Subscripting + labels = 💚. Mike’s original version uses the more conformant(¹) Int versus my rebellious UInt.

¹ This should be a term if it is not already.

7 Comments

  • I actually like you UInt better than the standard. I just don’t get what’s driving folks to allow use of invalid indexes. Any ideas?

    • They might have chosen Int so that it’s easier to extend Array, for example with Python-style negative indexing (i.e. for `a = [1, 2, 3, 4]`, `a[-1] == a[a.count – 1] == 4`). But if that was their intention, I don’t know why they didn’t just implement it themselves…

    • There are couple reasons why Int is preferred.

      1. Using Int everywhere simplifies API and reduces casting. Simpler code means less bugs.
      2. Arithmetics on UInt can underflow. For example let index = UInt(10) – 11 + 1 wont compile even when 0 is a valid index.
      3. 64-bit is the future so there is no need to save the one extra bit

      For more info check the discussion Why are APIs using Signed Integers where Unsigned Integers should be used? at https://devforums.apple.com/thread/263668 and especially the answers from Chris Lattner.

  • This could also be done with Ints using the pattern match operator ~=. This will match an int within a range:

    return 0..<count ~= index ? self[index] : nil

  • […] that returns a Deque, but I don’t like that. You could use labelled arguments. Erica Sadun has a cool post on using them with subscripts, and here’s what it would look like with […]

  • Is there a similar easy syntax for safely invoking removeAtIndex(index: Int) -> Element ?