Holy War: Last Item in a Non-empty Array

Thoughts? Preferences? For the context behind this, see this post, and the screenshots in particular.

Option 1:

extension Array {
    /// Return last element for array that is guaranteed 
    /// to have at least one element
    public var lastOrDie: Element {
        assert(!self.isEmpty, "Array is guaranteed nonempty")
        let finalIndex = self.index(before: self.endIndex)
        return self[finalIndex]
    }
}

Option 2:

extension Array {
    /// Return last element for array that is guaranteed 
    /// to have at least one element
    public var lastOrDie: Element {
        guard let final = self.last
            else { fatalError("Failed to retrieve final array element") }
        return final
    }
}

Option 3:

extension Array {
    /// Return last element for array that is guaranteed 
    /// to have at least one element
    public var lastOrDie: Element {
        return self.last! // yes that's an exclamation point
    }
}

Option 4:

array.last!

Option 5:

// postfix operators cannot begin with either a 
// question mark or an exclamation mark.
postfix operator .!!!

extension Optional {
    /// "This unwrap is intentional" operator.
    /// G. Paltrow: "Conscious Unwrapping"
    /// Courtesy of: http://twitter.com/lapcatsoftware/status/856902513303449601
    public static postfix func .!!!(lhs: Optional) -> Wrapped {
        return lhs!
    }
}

Option 6:

6 Comments

  • I’m not sure about my preferences, but for those who know Swift’s conventions, Array#last! feels like “lastOrDie” already. I think a function or computed property that just delegates to “last!” would be better off using the exclamation point explicitly at the call-site as opposed to being wrapped/redefined in the target.

  • I like #2. It’s explicit in what you’re doing, and I think it might be easy to miss the bang (!) at the end of the self.last! unless you’re looking for it.

  • foo.last!

  • Option 4 obviously: that’s Swift.

  • I’d use #4 in this case. For chaining, I might consider an unwrapper function to make it more clear in debugging *which* optional killed the run, but for a single access like this, it’s a non-issue.

  • I agree with everybody who said option 4. It’s already “last or die”. Why create a function that does the same thing. Option 1, by the way, is brain dead. Yes it prints a pretty message in a debug build, but in a debug build, you are likely to be in the debugger when it happens anyway.