SwiftQuest

Guide

Swift optionals, explained

What the ? on a type means, why Swift will not let you use one as a plain value, and the four ways to get the value out: ??, if let, guard let and ?..

A value, or nothing at all

An Int always holds a number and a String always holds text. But plenty of honest questions have no answer: who is at the gate, when nobody is? Swift builds a second type out of the first, written with a ?:

var arrival: String? = "Sable"
arrival = nil          // allowed: String? has room for "nothing"

var name: String = "Sable"
name = nil
// error: 'nil' cannot be assigned to type 'String'

String? is read "optional String", and it is not a String. It is a box that either holds a String or holds nothing, and nil is the word for the empty box.

Why Swift will not let you use it directly

let arrival: String? = "Sable"
print(arrival.count)
// error: value of optional type 'String?' must be unwrapped to refer to
//        member 'count' of wrapped base type 'String'

That refusal is the whole feature. A program that let this line through would work perfectly — until the day nobody turned up. Swift makes you say what happens then, before the program runs.

?? — the value, or a fallback

let arrival: String? = nil
print(arrival ?? "nobody")   // nobody

The optional goes on the left and what to use when it is empty on the right. The result is not optional: the emptiness has been dealt with.

if let — open the box if there is something in it

let arrival: String? = "Sable"
if let arrival {
    print("\(arrival) is at the gate.")   // Sable is at the gate.
}

Inside the braces arrival is a plain String; outside them it is optional again. (if let arrival { is short for if let arrival = arrival {.)

guard let — leave early, then carry on

func greet(_ arrival: String?) {
    guard let arrival else {
        print("Nobody at the gate.")
        return
    }
    print("Welcome, \(arrival).")   // a plain String from here on
}

greet("Sable")   // Welcome, Sable.
greet(nil)       // Nobody at the gate.

guard is the other way round from if let: its else must leave the function, so the unwrapped name stays available for everything below it. Use it to state what a function needs at the top, and keep the real work unindented.

?. — reach inside, if there is anything

let arrival: String? = "Sable"
let letters = arrival?.count   // an Int?: 5 here, nil with no name

And !, which you rarely want

! insists there is a value. When there is not, the program stops on the spot:

let arrival: String? = nil
print(arrival!)
// Fatal error: Unexpectedly found nil while unwrapping an Optional value

It is a promise about the future. One of the four ways above almost always says what you mean better.

Where SwiftQuest teaches it

Optionals are in Control Flow Keep, the second island, which is free. You predict what ?? prints, run a worked example where somebody (or nobody) is at the gate, and then write and repair functions with guard let until leaving early feels natural.

Learn it by writing it

SwiftQuest is a Swift course in fifteen islands. Every quest has you write real Swift and run it on a real compiler, in your browser, with nothing to install. It opens soon, and the first two islands are free.