Swift takes a strong stance on which types can be assigned nil
. For example, this is an error:
var i = 1 i = nil //error: nil cannot be assigned to type 'Int' // It is also an error for objects: var obj = NSObject() obj = nil //error: nil cannot be assigned to type 'NSObject'
Many languages struggle to express the notion of absence of value. The problem is that it is often implemented in a way that makes it indistinguishable from the integer 0
. It is also often easy to mistake for a pointer. Objective-C suffered from this, and there were several ways to indictate an item has no value: nil
, NULL
, NSNull
. For scalar values, something like NSIntegerMax
was often used.
Swift has a single way to express absence of value for all types. Conversely, nil
indicates the absence of a value and nothing else. The Optional
type is the canonical way to express this absence. It is impossible to mistake a nil
object with the number zero, or for a pointer to memory. You will never question whether a value is nil
or really 0.
This strict separation between value and absense-of-value means you can’t assign nil
just to anything. The literal nil
is assignable only to types which implement the protocol ExpressibleByNilLiteral
. And there is exactly one type in the standard library that implements that protocol: the Optional
enumeration. In other words, you can assign the value nil
only to Optionals.1 Because nil
is not a number, you can’t assign it to an Int
.
An Optional
is generic, so you can have Optional<Int>
, an Optional<Double>
, an Optional<NSObject>
and so on. The Optional is the type that can take a nil
assignment. An Optional<Int>
either has no value, or it has an intenger value, possibly 0
.
If you have an instance that might lack any meaningful value in its lifetime, declare it as an optional. When it has no meaningful value, assign it nil
.
var i: Int? = 1 // same as var i: Optional<Int> = 1 var j: Int? // uninitialized optionals are implicitly nil i = nil // Optional accepts nil assignment var obj: NSObject? = NSObject() obj = nil // Optional accepts nil assignment
Also note that these are three very diffent values:
let zeroValue: Int = 0 let nilOptional: Int? = nil let zeroOptional: Int? = 0 zeroValue == 0 // true zeroValue == nil // false nilOptional == 0 // false nilOptional == nil // true zeroOptional == 0 // true zeroOptional == nil // false
If you ever get a compiler error about assigning nil
to a non-optional, this is why. The benefit is that if you ever do encounter a nil
optional, you won’t have to second-guess whether the value is meant to indicate absence of value. This is true whether it it an object you created, or whether you received it from another library.
-
Implementing
ExpressibleByNilLiteral
on any other type is explicitly discouraged by Apple, and would break the semantic meaning ofnil
. Don’t do that. ↩