Optionals in Swift

 

Imagine we’re standing next to the river, looking out over the lily pads, and there are no frogs on any of them. We might represent this by

var frogsPerLilypad = 0

which means, “there is an integer number of frogs on each lily pad, and that number is currently 0.” But what if we wanted to say “there is either an integer number of frogs on each lily pad, or there isn’t”? In other words, we want to make a variable that can contain either a integer or nothing at all.1 In Swift, we would declare frogsPerLilypad like this:

var frogsPerLilypad : Int?

The variable frogsPerLilypad is now an optional: a variable that can either contain an actual value or nothing (nil). The type of the var is Int?. This means “optional integer.” Optionals are always typed. Int? means “an integer or nil,” Float? means “a float or nil,” etc. In the var declaration above, frogsPerLilypad can either be assigned a value of Int type or be assigned a nil. It’s initial value is nil.

Only optionals can be assigned to nil. We cannot, for example, do this:

var frogsOnLilypad1:Int = nil
because an Int must be an integer, and nil is not an integer. If we want to allow the possibility that lily

pad 1 will contain nil, we have to declare frogsonlilypad1 as an Int?.

Let constants can also be optionals, but there’s a subtle difference between let and var optionals. If add these two lines in the playground and look at the output,

we can see that the value of the var frogsPerLilypad is nil, but there is no value at all for the constant frogsonlilypad1 (not even nil). An unassigned var optional will initially have the value nil, but an unassigned let optional will not. This is so that the value can be assigned at some later point: remember that we can only assign a constant value once. The difference between var and let optionals will become extremely important when we talk about classes in the next chapter. Let optionals of primitive data types (like Ints and Doubles, for instance) are comparatively rare, but very commonly used for object types in Swift.

When we have an optional var, we often want to check it for nil and take some sort of action (maybe assigning it so some actual value). I’m jumping ahead a bit, but we can check if an optional is nil by

1 The distinction between 0 and nothing might seem trivial at this point, but bear with me. There really is a difference. And I told you this little talk was about nothing at all, didn’t I?

using code like this:

if (frogsPerLilypad == nil) { frogsPerLilypad = 1

}

Remember that frogsPerLilypad is an optional Int, it might be nil. So what we’re saying in this code is essentially “if frogsPerLilypad happens to be nil, assign it the value 1, otherwise, do nothing at all.” So if there are, for example, 173 frogs per lily pad, don’t do anything. Presumably the lily pad will tip over soon due to the great ribbitting mass of amphibians, at which point we can assign nil back to the optional.

Those of you accustomed to C (or Objective-C) may be thinking “ha ha. I know a better way to do that!” We’ll, the joke’s on you, because the code below doesn’t work at all:

if (!frogsPerLilypad) { frogsPerLilypad = 1

}

nil is not NULL, or Nil, or false, or even the Objective-C version of nil (see the sidebar below). The reason this code doesn’t work is that nil doesn’t evaluate to a boolean type (it’s not false as NULL is in C, it’s just “nothing at all.”) It’s all very zen. Chant with me now… nil is nothing… nil is nothing…

Before we come back to the real world2, there’s another way to check for optional nillity. Take a look at this code:

Setting aside the question of what a pirate ship might be doing amongst the lily pads, what do you think might be the result of this code if frogsPerLilyPad is nil?

“if let” is a form of the if statement that assigns the current value of an optional to a constant. In this case, regardless of whether frogsPerLilypad is nil or an actual integer, the value of numFrogs (which is a constant) will be assigned the current value of frogsPerLilypad. We could also have used numFrogs inside the if let construct, but I’m keeping it simple for now.

So if frogsPerLilypad is nil, numFrogs will be nil, and the if let statement evaluates false, and we’ll be sailing in a frog free sea. If frogsPerLilypad is an integer on the other hand (get it, “hand?” like deck- hand? All hands on deck? No? Never mind…) then the captain will be informed of the presence of frogs. Shiver me timbers.

If you are familiar with Objective-C, you’ll be tempted to think of nil as a pointer to a non-existent object. Don’t make this mistake. In Swift, nil means “no value.” Swift’s nil is not a pointer, it’s the absence of a value of a certain type. In Objective-C, only object types can be assigned to nil, because nil points to something (that is nothing) on the heap. In Swift, we can assign nil to any type; that is, there can be a nil value on both the stack and the heap.

2 In the sense of real types; we’ll still be pretty far out in terms of what most people regard as the “real world.”

This is not the same as saying

if (let numFrogs = frogsPerLilypad) { //…

}

In fact, we can’t say that at all in Swift, because (once again) nil cannot be interpreted as a boolean, and a lot of other reasons. (Typing the above in the playground will give you 8 errors, all of which boil down to “your syntax is really goofed up.”)

Unwrapping

Because an optional type is not the same as the concrete type on which it is based (Double? is not the same as Double for example), we have to do a bit more work to get the actual (non-nil) value out of an optional, if it has one. This process is called “unwrapping” the optional.

An optional like frogsPerLilypad will either contain an actual value (an Int in this case), or nil. If we know that there is an actual value because we’ve checked it with if (frogsPerLilypad != nil) or if-let, we need to unwrap the optional to get the value. This can be done by appending a ! to the optional, like this:

if (frogsPerLilypad != nil) { print(frogsPerLilypad!)

}

This uses the actual value “inside” the optional. Running the code above when frogsPerLilypad is 7 (for example) will print “7\n” (7 and a newline); leaving off the ! will print “Optional(7)\n”. In almost all cases, we want the value inside the optional, not the optional itself. A note of caution though… unwrapping an optional that contains nil results in an error, so always make sure the optional has a value (isn’t nil) before unwrapping it.

Appending a ! to an optional to get its value is called explicit unwrapping, because we’re explicitly saying we want the actual value rather than the optional. We can also tell optionals to implicitly unwrap themselves when we try to take their value by using a ! when we declare the optional:

var piratesOnShipWhoLikeFrogs : Int!

This says “when we take the value of piratesOnShipWhoLikeFrogs (assuming it’s not nil), take the actual value, not the optional.” But again, if we try to use the value of this var without assigning it first, we’re trying to unwrap an optional that has a nil value, and again, we’ll get an error, so we still need to check for nil:

We don’t have to put a ! after piratesOnShipWhoLikeFrogs in the print statement, but we still have to check for nil.

We’ll come back to optionals, unwrapping, and nil again and again. Swift optionals are not something

that can be ignored, so make sure you understand what we’ve covered so far about optionals before going on. About optionals, one thing at least can be said: optionals aren’t.

Leave a Comment: