Nil Coalescing Operator
Swift has a fun little formulation called the nil coalescing operator. Many languages have similar constructs, but in Swift it’s written as ??
and you use it like this:
let result = optionalValue ?? "default value"
It essentially says, “Unwrap the optional. If it’s a value, use it. If it’s nil
, use the supplied value, instead.” It’s really just a more concise way to say the following:
//Long-winded version of the above:
var result = "default value"
if let someFoo = optionalFoo{
result = someFoo
}
It’s important to note, though, that the right-hand side of the operator isn’t limited to being a simple literal or constant. In fact, it can be any sort of expression:
let result = optionalValue ?? calculateDefault()
The only limitation is that it must ultimatly evaluate to a value that has the same type as that represented by the optional. This, for example, is an error:
let stringOptional:String? = nil
let result = stringOptional ?? 42
//BOOM! Optional is a String but 42 is an Int
One fun consequence of ??
taking an expression for its right-hand argument is that you can chain nil coalescing operators together:
let result = maybe ?? possibly ?? "default"
Another thing we need to know about the nil coalescing operator is that, like Swift’s logical “and” and “or” operators, ??
short-circuits its evaluation. That is, if the optional isn’t nil
, it doesn’t need to know the value of the given expression, so it doesn’t evaluate it. This means we can put expensive operations there without worrying they’ll be called unnecessarily:
let result = cache ?? calculateAndCacheValue()
The nil coalescing operator wasn’t included in the first beta of Swift (it was added in beta5), and as such wasn’t in the original edition of The Swift Programming Language. As a result, it’s escaped many of ours' notice.
But it’s an incredibly important tool for increasing the readability of our Optional
code. And while all tools focused on concision can, of course, be taken too far1, we owe to ourselves (and those reading our subroutines) to keep ??
close at hand.
1: I recently found myself writing:
x = (value?["on"] as? NSNumber)?.boolValue ?? false
I don’t yet feel guilty about it, but imagine I will.↩︎