Understanding Optionals in Swift

Apple’s new Swift programing language brings along a couple of new tricks that make developing software easier, and safer, then ever before. However, one powerful feature, Optionals, can be confusing when first experienced. Optionals are a great way to ensure you are checking, and accounting for, possible nil values in your program early on during compilation. This way, you can have better guarantees that your application will work once it get’s into your user’s hands. In Swift, Optionals also have some nice interfaces that bridge the gap between legacy Objective-C libraries, while also keeping your code concise.

Getting Started

Let’s kickstart things by making a new playground in XCode (either iOS or OSX for platform is A-OK) called swift-optionals. You can zap the boilerplate and add the following code to see the two sides of Optionals in Swift.

import Foundation

var rightURL = NSURL(string: "http://www.reactive.io") // => {Some http://www.reactive.io}
var wrongURL = NSURL(string: "this is not a real url") // => nil

In this case, we’re trying to make a new NSURL object by popping in a string. However, we get something different for each case. For rightURL we got a Some result with a NSURL within. For wrongURL we instead got nil. In neither case, did we get a plain NSURL returned. This is a good thing, as a Some result will require explicit unwrapping, forcing us to check for nil values and account for them defensively. Let’s see how this works in practice.

Everybody Wants Some

If we look at the NSURL constructor in XCode, we see the following:

convenience init?(string URLString: String)

That question mark ? after init tells us that when constructed, NSURL is going to return an Optional. In Swift, Optional is an actual type, specifically a generic enum, that can either hold another object within, or be nil. Lets checkout what Optional looks like under the hood:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case None
    case Some(T)

    /// Construct a `nil` instance.
    init()

    /// Construct a non-\ `nil` instance that stores `some`.
    init(_ some: T)
...

Here we see that the Optional enum has two cases, None for nil and Some for the generic type specified. In Swift, we can make anything an Optional.Some by boxing it up:

Optional<String>.Some("really good stuff") // => {Some "really good stuff"}

On the other hand, None is equivalent for nil, which you can see here:

Optional<String>.None == nil // => true

In this way, you can think of Optional as a box, which may or may not contain the object that you specify. By sending a box to a method or function instead of its unwrapped contents, the compiler forces you to open the box and inspect what’s inside. If the box is empty, then you can catch the error and do something about it.

What are Generics?

In statically typed languages, Generics are types that can hold other arbitrary types. Going along with our box example, imagine how a shipper would want generic containers to hold their customer’s contents, but label them based on the content type within (e.g. fragile, perishable, hazardous, etc…). Making a new container for each type would be unnecessarily costly, and that’s no different in statically typed programming languages. Generics allow us to have similar container/label convenience in our code and reap the benefits of reuse.

Swift will implicitly infer the type of new variables and constants for you, which is a nice thing. But to make things more transparent, let’s explicitly set the generic types for our variables in two different (but equal) ways.

import Foundation

var rightURL: Optional<NSURL> = NSURL(string: "http://www.reactive.io") // => {Some http://www.reactive.io}
var wrongURL: NSURL? = NSURL(string: "this is not a real url") // => nil

For rightURL we used the long form way of using the Optional generic enum with a NSURL label. As Optional is a type we will use a lot, Swift gives us the shorthand form of just appending a ? to the end of the type, just like our NSURL initializer we talked about before. What happens if we try to gundeck our type by not adding a ? at the end?

import Foundation

var cheatURL: NSURL = NSURL(string: "http://www.reactive.io")

Trying to skip out on using an Optional gives us a compiler error with some interesting advice “Value of optional type ‘NSURL?’ not unwrapped; did you mean to use ‘!’ or ‘?’”. We know what the ? does in our code, but what about the exclamation mark !? Let’s check that out.

Implicit vs Explicit Optionals

Using the ? at the end of our type specifies an explicit Optional. Let’s instead end it with an ! and see what happens:

import Foundation

var implicitURL: NSURL! = NSURL(string: "http://www.reactive.io/tips") // => http://www.reactive.io/tips

Here we seem to be getting back an NSURL without a Some wrapper, but that is only half of the story. Using ! makes our implicitURL just as much of an Optional as rightURL. Just as Swift has implicit type inference, it also has implicit Optional unwrapping. This type, called ImplicitlyUnwrappedOptional responds just like a normal Optional, but the Swift complier will automatically unwrap it for you when used. This implicit unwrapping can make ImplicitlyUnwrappedOptional types a bit more dangerous as you don’t need to explicitly deal with nil values. But it can help bridge the gap when using legacy Objective-C interfaces that may initially have a nil value, but will always set it automatically when an application built.

We should now have four different Optional URLs to unwrap and work with, in review:

import Foundation

var rightURL: Optional<NSURL> = NSURL(string: "http://www.reactive.io") // => {Some http://www.reactive.io}
var wrongURL: NSURL? = NSURL(string: "this is not a real url") // => nil

var implicitURL: NSURL! = NSURL(string: "http://www.reactive.io") // => http://www.reactive.io/tips
var explicitURL: ImplicitlyUnwrappedOptional<NSURL> = NSURL(string: "this is another bad url") // => nil

Let’s Check This Out

One way to check out the existence of an Optional is to explicitly see if it is nil. Add the following below our current code and let’s see what we get.

if rightURL != nil {
    println("got a URL: \(rightURL)") // => "got a URL: Optional(http://www.reactive.io)"
}
else {
    println("no URL, sorry :(")
}

Well, were getting there, but Optional(http://www.reactive.io) is not what we wanted. If we do have something in our Optional, how do we get it out? This is where the ! symbol starts to pull double duty. For any Optional object, an ! appended on the variable or constant name will force it to become unwrapped, and raise an error if it is nil. Let’s give that a try:

if rightURL != nil {
    println("got a URL: \(rightURL!)") // => "got a URL: http://www.reactive.io"
}
else {
    println("no URL, sorry :(")
}

There we go, we are now handling our Optional unwrapping in a very safe way, but there is another way by using an if let block. Give the following a try:

if let url = rightURL {
    println("got a URL: \(url)") // => "got a URL: http://www.reactive.io"
}
else {
    println("no URL, sorry :(")
}

Here, we are setting the url constant to an unwrapped NSURL value, only if there happens to be one in our rightURL Optional. If not, we have our default. Now, try switching rightURL to wrongURL, implicitURL and explicitURL and notice what happens. When we were dealt a nil, our program does not crash and instead tells us there is no URL to print. Furthermore, ImplicitlyUnwrappedOptional values act just like our explicit Optional values, making them interchangeable.

If you wanted to ditch if conditions, you can also use Swift’s switch statement as well:

switch rightURL {
case nil:
    println("no URL, sorry :(")
default:
    println("got a URL: \(rightURL!)")
}

And if switch statements are still too verbose, we can also use the nil-coalescing operator ?? to further catch nil values in our code and set sensible defaults. Take a look at this:

var myURL = wrongURL ?? explicitURL ?? rightURL // {Some http://www.reactive.io}
println("got a URL: \(myURL!)") // => "got a URL: http://www.reactive.io"

If we can be sure that our rightURL will always have a correct NSURL (i.e. by hard-coding it), this can be an easy way to assign variables that you can be sure are not nil.

Have Some Class

Now that we’ve worked with Optional types procedurally, its time to see how we can use them to build object oriented code. Go ahead and replace all the code in our playground with the following:

import Foundation

class Person {
    var name: String
    var address: String

    init(name: String, address: String) {
        self.name = name
        self.address = address
    }

    func description() -> String {
        return "\(name) @ \(address)"
    }
}

class Box {
    var contents: String
    var sender: Person!
    var recipient: Person?

    init(contents: String) {
        self.contents = contents
    }
}

var alice = Person(name: "Alice", address: "New York City")
var book  = Box(contents: "A Good Book")

book.sender = alice // => {name "Alice" address "New York City"}

Notice in our Box class, the sender property is an ImplicitlyUnwrappedOptional, and the recipient property an Optional. If you try to make either a plain String, the Swift compiler will give you an error. This is because these two properties were not set in the initializer, and as such will be nil for part of an objects lifecycle. For this example, Alice has a book boxed up and ready to send, but does not yet know who to send it to. The Swift compiler might be a bit overzealous in this example as this code immediately sets sender to alice right after a new Book object is constructed. But, when not set during initialization, Optional types are in fact non-optional. Cases like this can make the ImplicitlyUnwrappedOptional a good choice, as the compiler will be happy with getting an Optional, and you can treat it as either a plain type or an Optional one in your code.

Method Call Me, Maybe?

If we want to get the description of Box’s sender or recipient, we might run into some trouble. This is because we cannot call a description method on nil, and risk raising an error if we force unwrap an Option with !. Also, conditional statements using if and else might be too verbose for one off method calls. This is where Swift gives us another tool by using the ? operator for Optional Chaining. Here, we check the existence of an property before calling a method on it. Let’s give it a go by adding the following below our Person and Box code.

book.sender?.description() // => {Some "Alice @ New York City"}
book.recipient?.description() // => nil

Good to go, we got right to calling our description method, but only if it was there. Furthermore, we got an Optional in return, which we can then use later. Optional Chaining also works great when we want to call methods that mutate their receiver, but only if there is something to mutate. Lets Add Bob as a recipient now and see what happens.

book.recipient = Optional(Person(name: "Bob", address: "San Francisco"))

Here, we are setting our Optional recipient to a new Person, in this case Bob. Good news is that both Optional and ImplicitlyUnwrappedOptional types can infer what you need, making the Optional constructor unnecessary, and our new call can look like this:

book.recipient = Person(name: "Bob", address: "San Francisco")

if let note = book.recipient?.description() {
    println("Hey \(note), enjoy the Book!") // => "Hey Bob @ San Francisco, enjoy the Book!"
}

Hope Bob gets a good read out of it!

Summary

We went through a lot, but got to the core parts of what Optionals are in Swift, and how they make your code more reliable. We also dug deeper into how Optionals can be used both explicitly and implicitly, which will help as you to use them in your code, and in the many libraries that will utilize them. All together, the different ways Optionals can be used will keep you coding faster, while having more fun and less run-time frustration!