Swift Optionals

How Swift “Defines Away” Common Programming Errors…Sort Of


Eight pages in to Apple’s new Swift language book, there’s a passing mention of “optional” values, and how these values can be nil. What you might have missed is that this also means that non-optional types can never be nil. Coming from Objective-C or even Java or C#, this may seem surprising (it was for me):

var me: String = “Matt”
me = nil // Compile-time error

Objects that may or may not be nil (and the nil-checking code that accompanies them) are the cause of many common programming errors. Swift’s optionals offer compile-time cues to developers about when it’s necessary to nil-check and when it’s not, and makes it harder to write code that misbehaves in the presence of nil.


Unwrapping

One of these compile time cues is that you can’t use the value of a variable with an optional type directly:

class Person {
var name: String
init(_ name: String) {
self.name = name
}
}
var p: Person? = Person(“Matt”)  // p is optional/nil-able
var greeting = “Hello “ + p.name // Compile-time error

In other languages like C# or Java, code like this compiles fine, but throws a runtime exception when p is nil. It’s all too easy to mistakenly assume that a variable couldn’t possibly be nil, only to be bitten by an uncaught NullReferenceException down the road.

In Swift, we have to make that assumption of non-nil explicit. Here’s how you’d achieve the same result in Swift:

var greeting = “Hello “ + p!.name // “Hello Matt”

The ‘!’ operator unwraps the optional and exposes the underlying value (in this case the string “Matt”). If p is nil, this produces a runtime error, just like C# or Java. The difference is that here, the developer is opting in to this type of unsafe behavior by adding the exclamation point.

It’s safer and preferable to use “optional binding” to unwrap an optional:

if let unwrappedName = p.name {
var greeting = “Hello “ + unwrappedName
} else {
var greeting = “Hello stranger”
}

The compiler recognizes the assignment expression in the if statement, and unwraps the right-hand-side. If the value is nil, the assignment doesn’t occur and the expression evaluates to false.


Some Rough Edges

I’ve found a few places where Apple has hidden the complexity of unwrapping optionals, and I think this will cause confusion for those learning Swift. For instance, neither println nor string interpolation require optional strings to be unwrapped, but concatenation does:

var you: String? = "Reader"
var greeting = “Hello \(you)” // No compiler error!
print(“Hello “); println(you) // Also fine.
var nope = "Hello " + you // Compiler error

Swift also allows the developer to hide some of this complexity by using implicitly unwrapped optionals. These can be nil just like a normal optional, but is automatically unwrapped when it is used, which may result in a runtime error (exactly as if you had placed an exclamation point after the variable).

Since Objective-C objects can be nil, all objects returned from Objective-C APIs are returned as implicitly unwrapped optionals. This simplifies consuming Objective-C APIs, however it removes the benefit of compile-time cues for proper nil-checking mentioned above. This can lead to some unexpected behavior if you forget to nil-check:

let formatter = NSDateFormatter()
let now = formatter.dateFromString(“not_valid”)
let soon = now.dateByAddingTimeInterval(5.0) // Runtime error.

In the equivalent Objective-C code, ‘soon’ would be nil, rather than producing a runtime error. Fortunately the nil-check code is just a simple if statement:

if let soon = now.dateByAddingTimeInterval(5.0) {
// soon is a concrete NSDate
} else {
// soon is nil
}

More Reading

There’s much more about optionals in Apple’s free ebook The Swift Programming Language. I also found it very helpful to look at the Swift header definitions available in the Xcode6 Beta, especially at the types Optional<T> and ImplicitlyUnwrappedOptional<T> (for which the ‘?’ and ‘!’ type modifiers are syntactic sugar).

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.