More on the Optionals!

We can chose to write stable code or we can hand-wave stuff that “shouldn’t fail”. I’m extremely wary of the pattern that I keep seeing from Apple about ! and Optional… I find it odd that Apple is promoting the use of the ! pattern.

An initializer defined with init can be made failable by adding a ? or a ! after the init, which indicates the form of optional that will be produced by constructing an object with that initializer. For example, one could add a failable initializer to Int that attempts to perform a conversion from a String:

extension Int {
    init?(fromString: String) { 
        if let i = fromString.toInt() {
            // Initialize 
            self = i
        } else {
            // return nil, discarding self is implied
            return nil
        }
    }
}

Source: Apple Developer Blog: https://developer.apple.com/swift/blog/

If we change the init? above to init! (which the description above tells us is perfectly valid)…

let value = Int(fromString: "abc")
return value + 1

BOOM! Hello my EXC_BAD_INSTRUCTION friend.

Look, sometimes your code really should only return nil in the most dire of circumstances, ok… but is the right behavior to crash your app? Even if it is, it should not be so easy to enable the return of nil from something that should practically never return nil, such as memory allocations handled by the system.

One of Swift’s goals is this: “Understanding and properly handling cases where objects are nil is fundamental to the frameworks, and Swift code makes this extremely easy.” (Source: https://developer.apple.com/swift/)

I truly believe this behavior is leading us away from that – I’d go so far to claim it’s the antithesis of it, but that may be too extreme for some.

As developers, we want to be able to write both safe and stable apps. The ! is leading us down the path of safe but crashy apps. We’re going to get there just as we got there with * and dereferencing null pointers. Of course, everyone knows not to do it… yet sometimes we forget. And to those new to the language, they might not know better.

See: Pointer fun with Binky.

I would much rather see APIs defined like this:

@unsafe_force_unwrap func init(fromString: String) { ... }

Give support for the feature when needed, but people will be much less prone to accidentally doing it. It needs to be marked as unsafe; currently there is no really indication other than experience with the language.

This also gives us the ability to have compiler warnings/errors when these are used so we can much easier audit those code usages.

More on the Optionals!