Optionals
Swift's way of making "there might be nothing here" a fact the compiler checks.
An optional is a box that either holds a value or holds nothing. String always has a string in it. String? might have a string, or might be nil.
This sounds small, and it changes everything. In a language without optionals, any object reference might secretly be null, and you find out at runtime when it crashes. In Swift, a type that can be absent *says so in its name*, and the compiler refuses to let you use the value until you've handled the empty case.
So nil doesn't disappear. It becomes visible, and the compiler starts helping you.
var nickname: String? = nil // the box is emptynickname = "Ada" // now it holds a value
// Optional binding: open the box, and only run if something was insideif let nickname { print("Hello, \(nickname)") // nickname is String here, not String?}
// guard: leave early when the box is emptyfunc greet(_ nickname: String?) -> String { guard let nickname else { return "Hello, stranger" } return "Hello, \(nickname)"}
// Nil-coalescing: a default when the box is emptylet display = nickname ?? "Anonymous"
// Optional chaining: do nothing gracefully if anything along the way is nillet initial = nickname?.first // Character?let shout = nickname?.uppercased() // String?
Show all 20 linesShow less
var nickname: String? = nil // the box is emptynickname = "Ada" // now it holds a value
// Optional binding: open the box, and only run if something was insideif let nickname { print("Hello, \(nickname)") // nickname is String here, not String?}
// guard: leave early when the box is emptyfunc greet(_ nickname: String?) -> String { guard let nickname else { return "Hello, stranger" } return "Hello, \(nickname)"}
// Nil-coalescing: a default when the box is emptylet display = nickname ?? "Anonymous"
// Optional chaining: do nothing gracefully if anything along the way is nillet initial = nickname?.first // Character?let shout = nickname?.uppercased() // String?Under the hood
Optional isn't compiler magic. It's an ordinary enum in the standard library:
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
String? is sugar for Optional<String>, nil is sugar for .none, and optional binding is sugar for pattern-matching .some. That's why you can switch over an optional, and why Optional gets map and flatMap like any other container.
The compiler does add one optimisation worth knowing: for class references and other pointer-shaped types, an optional costs *no extra memory*. The all-zeroes pointer is reused to mean .none. This is called a spare-bit representation. So UIView? is the same size as UIView — you're not paying for the safety.
An Optional<String> branches into two cases: .some, holding the string "Ada", which flows to safe use; and .none, which flows to a default value.
An optional is one of exactly two cases.
- An optional is one of exactly two cases.
- If a value is present, binding gives you the unwrapped type.
- If it's nil, you must say what happens instead — the compiler won't let you skip it.
Quick check
What does if let name = maybeName actually do?
- Checks whether maybeName is not nil, leaving it optional inside the block
- Binds the unwrapped value to a new non-optional constant, and runs the block only if a value was present
- Crashes if maybeName is nil
- Converts maybeName to an implicitly unwrapped optional
Reveal answer
Binds the unwrapped value to a new non-optional constant, and runs the block only if a value was present
Optional binding pattern-matches the .some case and binds its associated value. Inside the block name has the *wrapped* type — String, not String? — which is the whole point: after the check, the compiler knows a value exists. It never crashes; the nil path simply skips the block.
Interview question
When is force-unwrapping with ! a reasonable choice, and when is it a bug waiting to happen?
Think first, then reveal
! is an assertion that a value cannot be absent. It's reasonable when absence would mean the program is already broken and you want to fail loudly and immediately: a resource you ship inside your own bundle, a storyboard outlet that must be connected, an invariant established two lines above. In those cases a crash on the developer's machine during the first run is *better* than silently degrading.
It's a bug waiting to happen the moment the value's absence depends on anything outside your control — a server response, user input, a file on disk, a cache that may have been evicted, a view that may not have loaded yet. Those aren't programmer errors, they're expected states, and they deserve guard let and a real fallback.
The test I apply: can I write down the invariant that guarantees this is non-nil, and is that invariant enforced by code I own? If not, don't force it.
What an interviewer listens for
- Distinguishes programmer error from expected runtime absence
- Names concrete legitimate uses rather than saying "never use it"
- Recognises crashing early can be preferable to silent corruption
- Mentions that data from outside the process is never a candidate
Key takeaway
An optional makes absence part of the type, so the compiler forces you to decide what happens when there's nothing there. Every ! you write is you taking that decision back off the compiler and onto yourself.