Optional?

You might have overheard Swift developers talk about how great Optionals are. Optionals are a foundational feature of Swift, and once you know how to use them, you probably wouldn’t even want to work with a language that doesn’t support it. If you’ve ever had your app crash because your code allowed nil to be inserted into a NSDictionary 💣 or had text in a UILabel show up as (null) or anything else bad caused by nil, you’ll love optionals even more.

Let’s start with a small example. (I recommend downloading the Playground project or cloning the repo and following along!) Let’s say you want to model a Person, and you want a person to have a given name, family name, and middle name. You might define such a Person like this:

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String
}

Now, I can create a Person to represent myself. I don’t have a middle name, so I’m going to pass in nil for that.

let me = Person(givenName: "Ayaka", familyName: "Nonaka", middleName: nil)

Hmmm. I got an error message: Nil is not compatible with expected argument type 'String'.

This is because the Swift compiler is warning us, “Hey, middleName can’t be nil because you didn’t say it could be nil!” But how do we tell the compiler that it’s OK for middleName to be nil?

That’s where Optional comes in. We can redefine Person as below:

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String?
}

Notice that now middleName is of type String? instead of String. This means that middleName can be a String or nil. Now

let me = Person(givenName: "Ayaka", familyName: "Nonaka", middleName: nil)

should compile without error.

Let’s take it a little further and add a computed variable that returns a Person’s display name. For example, mine would be “Ayaka Nonaka” or if I had a middle name, maybe “Ayaka Chewbacca Nonaka” or something like that. 🙊

struct Person {
    let givenName: String
    let familyName: String
    let middleName: String?
    
    var displayName: String {
        return givenName + " " + middleName + " " + familyName
    }
}

Slight problem here. This doesn’t compile! 😭

You get a somewhat cryptic warning Value of optional type String? is not unwrapped; did you mean to use '!' and '?'. You even get a friendly looking Fix-it from Xcode to Insert ”!”. It’s a trap. Don’t do it!

The ! suffix is used for “force unwrapping” optionals, and you’re telling the compiler that you swear that this will never be nil, even though it’s an optional. If you’re not careful, this can lead to runtime crashes which is really not fun when it happens in production when it crashes for your users.

So how do we appease the compiler without yelling! at! it! by! force! upwrapping? If you’re coming from another language, your first instinct might be to check for nil like below:

var displayName: String {
    if middleName != nil {
        return givenName + " " + middleName + " " + familyName
    } else {
        return givenName + " " + familyName
    }
}

But you’ll notice that we get the same error message as before. The problem is that even though it might look obvious to you that middleName can’t be nil within the if, it’s not obvious to the compiler.

If you thought if statements were useful, wait until you see this one. Introducing… if let!

if let

An if let statement looks something like this:

if let x = y { // where y is Optional
    A(x) // Do something with non-Optional x
}

You can read this as: If y has a non-nil value, assign it to x and execute A and it’s guaranteed that x is non-nil.

In our case, we can rewrite displayName as below.

var displayName: String {
    if let middleName = middleName {
        return givenName + " " + middleName + " " + familyName
    }
    return givenName + " " + familyName
}

You might notice that we used the same variable middleName for the left and right-hand sides of the if let. We could have written if let actualMiddleName = middleName or something like that to make it very clear that the left handside is the non-optional, but I personally prefer using the same name for both because it’s cleaner and easier to read. (Download the if let solution.)

There’s one more thing I want to show you. They’re called guard statements.

guard 💂🏼

If I had to choose a favorite feature that was introduced in Swift 2.0, it’s guard. A guard statement looks like this:

guard let x = y else { // Where y is Optional
    A(y) // Do something with y as nil
}
// Do something with non-Optional x

You can read this as: If y has a non-nil value, assign it to x. Otherwise, execute the else clause assuming y is nil. Below the guard, you can use x which is guaranteed to be non-nil.

Let’s see how we can rewrite displayName using guard instead of if let. It might look something like this:

var displayName: String {
    guard let middleName = middleName else {
        return givenName + " " + familyName
    }
    return givenName + " " + middleName + " " + familyName
}

That looks pretty similar to our if let example. Why would we even use it over if let then? Let’s look at a slightly more complex example.

When we make apps, we often have a backend API that we are communicating with. The API sends us back data (often in JSON format), and we have to convert that to something that we can work with on the client side. In our Person example, it might be nice if we can initialize a Person using a JSON dictionary that we get back from the API. First let’s see what this might look like using if let.

init?(dictionary: NSDictionary) {
    if let givenName = dictionary["given_name"] as? String,
        let familyName = dictionary["family_name"] as? String {
            self.givenName = givenName
            self.familyName = familyName
    } else {
        return nil
    }
    self.middleName = dictionary["middle_name"] as? String
}

A couple of things to point out here:

  1. Yes, if let lets you assign multiple values at once. It’s awesome.
  2. init with a ? is known as a failable initalizer. We won’t get into it here, but if you want to read more about them, Apple’s Swift blog has a great post about it.

Anyway, yikes. I don’t know about you, but this looks pretty complicated for something that does a relatively simple task. What’s going on here? First, we’re seeing if dictionary["given_name"] is a String (non-nil since it’s not String?) and assigning it to givenName and doing the same for dictionary["family_name"] for familyName. If both of these are non-nil we assign to their respective properies. Otherwise, we return nil and fail the initializer. Finally, we set middleName outside of the if let because we’re fine if middleName is nil since it’s of type String?.

We can do better than this. Let’s see what this would look like with guard.

init?(dictionary: NSDictionary) {    
    guard
        let givenName = dictionary["given_name"] as? String,
        let familyName = dictionary["family_name"] as? String
    else { return nil }
    
    self.givenName = givenName
    self.familyName = familyName
    self.middleName = dictionary["middle_name"] as? String
}

Before we dive into the code itself, step back and look at it for a second. Compare it to the if let solution. Doesn’t it just look cleaner?

Just like the if let example, we’re first seeing if dictionary["given_name"] is a String and assigning it to givenName and doing the same for dictionary["family_name"] for familyName. Unlike the if let example, if either of these turns out to not be String, it falls into the else clause and fails the initializer, because we don’t ever want to end up with a Person without a givenName and familyName.

Now below the guard we can happily work with givenName and familyName knowing that they are both String and assign them to their respective properties. As for middleName, its type is String? so we’re fine if it’s nil and we don’t have to guard against its being nil.

This is clean and easier to understand because the “happy path” where a Person can be created is all in one place, unindented, unnested, and easier to follow. (Download the guard example.)

Isn’t guard so nice? I didn’t think working with JSON dictionaries could be this pleasant without having to rely on frameworks like Mantle (which was a must have for me for Objective-C). If you want more information about errors though, like when the API starts returning data with missing fields and you’re trying to figure out what’s missing, you might want to check out Argo.

That’s it for now. If you have any questions, feel free to leave them in the comments below, or tweet at me @ayanonagon. The biggest reason I’m writing these posts is to get better at explaining concepts and how amazing they are, so any feedback about what was clear vs. not would be much appreciated as well. Also let me know what other topics you want to hear about. Hope you had fun learning, and thanks for reading!

More Reading