Chris Castiglione Co-founder of Console.xyz. Adjunct Prof at Columbia University Business School.

Swift Tutorial: Optionals for Beginners

4 min read

Swift Optionals

Optionals are a powerful feature of the Swift programming language. They can be difficult to understand and use effectively. Let’s review the essentials.

At a high level, what are Optionals?

Let’s say a mutual friend is throwing a Halloween party. The invitation outlines the pertinent details (e.g. time and location) and among other things it says, “bring a beverage, costumes optional.” Now if we wanted to represent this party and its guests in code, we might create a Party object and a Guest object. We might also translate the above details into properties on these classes. However, in order to accurately represent this Halloween party, we want to express the fact that costumes are optional. We do this like so:

class Party{var time: NSDatevar location: CGPointvar guests: Array // …} class Guest {var beverage: String // Each guest must have a beveragevar costume: String? // Each guest can choose to come in costume or plain clothes (i.e. costumes optional)// …}

view rawswift-optionals-1.swift hosted with ❤ by GitHub

In Swift, the ? is how we designate a variable as Optional. And this just means that it’s okay for the variable to have a value costume = "Frankenstein" or to not have a value costume = nil. In contrast, every guest must have a beverage, this is expressed by the absence of a ?, and the compiler will enforce this for us.

A little background

Optionals work in tandem with variables. A variable is a construct that we use to hold onto a piece of data. At a minimum we usually give a variable a name, type and value.

// Here we explicitly specify the typevar beverage: String = “Leffe” // But the type can also be inferred from the fact that we’re assigning it a String valuevar name = “Leffe”

view rawswift-optionals-2.swift hosted with ❤ by GitHub

vars and lets

Swift offers us two distinctly different kinds of variables: vars and lets. In order to understand Optionals we must first understand vars and lets.

The primary distinction between vars and lets is that vars are mutable and lets are immutable. In other words, we can change the value of a var as many times as we want, but once we set the value of a let, we can never change it. Let’s look at some examples.

// varsvar mutableBeverage = “Leffe”println(mutableBeverage) // “Leffe”mutableBeverage = “Bud”println(mutableBeverage) // “Bud”mutableBeverage = mutableBeverage + “weiser”println(mutableBeverage) // “Budweiser”// letslet immutableBeverage = “Bud”println(immutableBeverage) // “Bud”immutableBeverage = “Leffe” // Compiler errorimmutableBeverage = immutableBeverage + “weiser” // Compiler error

view rawswift-optionals-3.swift hosted with ❤ by GitHub

Test these out in a Swift Playground and you’ll see that the compiler enforces these mutability rules for us. And in doing so it forces us to be explicit about our intentions. If we used vars alone we’d be wandering into a lawless land. Mad Max territory. Variables that we intend to be immutable might unintentionally be mutated. But in this day and age we can elect to use vars and lets where appropriate, and proceed with confidence.

Something and Nothing

Optionals add a layer of complexity to vars and lets. They modify vars and lets to make a distinction between variables whose value can be either something or nothing, and variables whose value can be something but never nothing. In the context of Swift, nothing is expressed with nil, the absence of a value. Let’s look at some examples.

// Non-optional varsvar mutableBeverage = “Leffe”println(mutableBeverage) // “Leffe”mutableBeverage = “Bud”println(mutableBeverage) // “Bud”mutableBeverage = mutableBeverage + “weiser”println(mutableBeverage) // “Budweiser”mutableBeverage = nil // Compiler error// Optional varsvar mutableCostume: String? = “Dracula”println(mutableCostume) // Optional(“Dracula”)mutableCostume = “Frankenstein”println(mutableCostume) // Optional(“Frankenstein”)mutableCostume = “Bride of “ + mutableCostume!println(mutableCostume) // Optional(“Bride of Frankenstein”)mutableCostume = nil // nil// Non-optional letslet immutableBeverage = “Bud”println(immutableBeverage) // “Bud”immutableBeverage = “Leffe” // Compiler errorimmutableBeverage = immutableBeverage + “weiser” // Compiler errorimmutableBeverage = nil // Compiler error// Optional letslet immutableCostume: String? = “Dracula”println(immutableCostume) // Optional(“Dracula”)immutableCostume = “Frankenstein” // Compiler errorimmutableCostume = “Bride of “ + immutableName! // Compiler errorimmutableCostume = nil // Compiler errorlet anotherCostume: String? = nil println(anotherCostume) // nil

view rawswift-optionals-4.swift hosted with ❤ by GitHub

Note the addition of a question mark to our variable declaration. The question mark signifies that the variable is an Optional, a variable that can be something (a value) or nothing (nil). Without the question mark these variables can never be nil. Note that declaring a variable as Optional does not effect its mutability. vars remain mutable and letsremain immutable.

Also note the use of an exclamation mark in select locations. The exclamation mark is a heavy-handed way to unwrapi.e. gain access to the value that an optional variable holds.

Unwrapping Optionals

Allowing variables to be either something or nothing injects risk into our programs. If we assume a variable is something and it turns out to be nothing, our program might behave unpredictably. Or worse yet crash. To mitigate this risk and avoid having to make assumptions, we want to know definitively whether a variable is something or nothing before working with it. Anyone who has worked with Objective-c is familiar with this upfront runtime check.

NSString *costume = @”Dracula”; // …if (costume == nil) {// Do something for this plain clothes guest} else {// Do something else for this costumed guest}

view rawswift-optionals-5.swift hosted with ❤ by GitHub

Swift Optionals allow this check to happen at compile-time. If we attempt to use an optional variable withoutunwrapping it, the compiler will throw an error instructing us to first unwrap the value. Which means that the compiler will never let us use an optional value without first being certain that it is something or nothing.

We can safely unwrap optionals like this:

var costume: String? = “Werewolf”println(costume) // Optional(“Werewolf”)costume = costume + “ dressed as Michael J Fox” // Compiler Errorif let something = costume {// The value is not nil, use it with confidencesomething = something + “ dressed as Michael J Fox”println(something) // “Werewolf dressed as Michael J Fox”} else {// The value is nil}

view rawswift-optionals-6.swift hosted with ❤ by GitHub

A heavy-handed way to unwrap an optional is to make use of the exclamation mark. This is called force unwrapping:

var costume: String? = “Werewolf”println(costume) // Optional(“Werewolf”)costume = costume! + “ dressed as Michael J Fox” println(costume) // Optional(“Werewolf dressed as Michael J Fox”)

view rawswift-optionals-7.swift hosted with ❤ by GitHub

The former is greatly preferred to the latter. By force unwrapping the optional, we’re asserting that we’re positive the variable is not nil. But if we’re wrong our program will crash. Force unwrapping puts the onus back on us humans. To keep track of what is nil and what is not, and in doing so brings all of the risk and assumptions back into our code.

Optionals in Practice

So when do we use Optionals? We use Optionals when a nil value is meaningful.

Consider the case of a model object in our iOS app that represents a video on our server. If the video’s image_urlproperty is non-nil we know it has a thumbnail image that we can use. And if it’s nil we know it doesn’t.

Or consider the case of an NSError object passed as an argument to a network call’s completion handler. Not every network call will return an error, so it makes sense for this error object to be Optional.

On the other hand, our program might make use of a Person object. And it might require that every Person have anage. In this scenario age would be non-optional, passed into the Person constructor and never allowed to be nil.

Summary

In Swift, we have four different kinds of variables at our disposal:

  • vars (mutable, never nil)
  • Optional vars (mutable, nilable)
  • lets (immutable, never nil)
  • Optional lets (immutable, nilable)

This simple toolset empowers us to write clearer code and more stable programs. And it allows the compiler to be a better partner in helping us achieve these goals.

Learn to Code Comment Avatar
Chris Castiglione Co-founder of Console.xyz. Adjunct Prof at Columbia University Business School.