Optionals in Swift
6 ways to use Optional type in Swift. How many of these methods do you already know? The last one may surprise you!
Introduction
Object references in many programming languages can point to the real object or not point to anything (i.e. they are Null). Swift, conversely, does not have null object references. The references must always point to a real object. To support the “can have absence of a value” feature, Swift has a different solution - the Optional type, which is an enum of two cases.
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
Optional either holds no value or some value. The none enum case denotes the absence of a value and the some enum case denotes presence of value. The value is stored as Wrapped, which is the generic placeholder type for the actual user define type of the value. Now anytime we have a need to use null, we can use Optional.
Creating Optionals
Lets use an example from an imaginary cat experiment.
func openSchrodingersBox() -> Optional<Cat> {
if poisonFlaskShattered {
return .none
} else {
return .some(Cat(name: "Shady"))
}
}
This function can return both a value and none. Swift gives three helpful syntax simplifiers: (a) the special constant “nil” having the value Optional.none, (b) the question mark (?) operator to define the optional type instead of typing the full name Optional<Cat>, and (c) no need to specify .some.
func openSchrodingersBox() ->
Cat? {
if poisonFlaskShattered {
return
nil
} else {
return
Cat(name: "Shady")
}
}
This way all the implementation details of the Optional enum is completely hidden from the programmer, and they can just work with nil and ?.
Unwrapping Optionals
Optional instances in Swift must be “unwrapped” before their values can be used. Unwrapping means extracting out the stored value. There are 6 ways to unwrap optional values. The following use the example function above to get a cat which may or may not be alive.
let maybeAliveCat:
Cat? = openSchrodingersBox()
1. Optional Binding
The first way you can unwrap an optional is use if-let to find out whether an optional contains a value, and if so, unwrap that value as a new variable. This is called optional binding.
if let aliveCat = maybeAliveCat {
aliveCat.meow()
}
In this example the scope of aliveCat is only within the body of the if statement.
2. Guard Statement
You can use guard-let-else statement to also check if optional contains a value. The guard statement has an else clause. The code inside the else clause is executed if the optional doesn’t have a value. If the optional has a value, it is available in the lines of code that follow the guard statement.
guard let aliveCat = maybeAliveCat
else {
return
}
aliveCat.meow()
Using guard statement lets you early exit a method if value is not present. It improves the readability of the code compared to doing the same check with an if-let statement.
3. Nil-Coalescing Operator
The third way you can unwrap an optional is using the nil-coalescing operator (??). This lets you provide a default value if optional is nil.
let aliveCat = maybeAliveCat ?? defaultCat
aliveCat.meow()
4. Optional Chaining
Next, you can also unwrap by placing a question mark (?) after the optional. This is called optional chaining.
maybeAliveCat?.meow()
If the optional contains a value, the meow() call succeeds; if the optional is nil, the method meow() is never executed. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.
5. Forced Unwrapping
So far we have looked at safe ways to unwrap optionals. These next 2 are unsafe, and should be used when you’re sure that an optional contains a value. First of these is to force unwrap an optional’s underlying value by adding an exclamation point (!) to the end of the optional’s name.
maybeAliveCat!.meow()
This is similar to optional chaining using ?. But the difference is that optional chaining fails gracefully when the optional is nil, whereas trying to use ! to access a nonexistent optional value, triggers a runtime error. Therefore, forced unwrapping is generally not recommended.
6. Implicit Unwrapping
Finally, sometimes it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time. These kinds of optionals are declared using exclamation mark instead of a question mark, and are called as implicitly unwrapped optionals.
let aliveCat: Cat! = maybeAliveCat
aliveCat.meow()
This way optionals are unwrapped automatically and can be used like non-optional values, without the need to unwrap them each time they’re accessed. However, if an implicitly unwrapped optional is nil and you try to access its wrapped value, you’ll trigger a runtime error.
Conclusion
Tony Hoare invented the Null reference in 1965 as part of the ALGOL W language. He later called it as a “billion-dollar mistake”, saying
…it has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
I cannot say if Swift optionals have saved a billion dollars, but I hope at least this article helped you in understanding how they work. Feel free to contact me if you have any questions or comments.