Apple’s new Swift programing language brings along a couple of new tricks that make developing software easier, and safer, then ever before. However, one powerful feature, Optionals, can be confusing when first experienced. Optionals are a great way to ensure you are checking, and accounting for, possible
nil values in your program early on during compilation. This way, you can have better guarantees that your application will work once it get’s into your user’s hands. In Swift, Optionals also have some nice interfaces that bridge the gap between legacy Objective-C libraries, while also keeping your code concise.
Let’s kickstart things by making a new playground in XCode (either iOS or OSX for platform is A-OK) called
swift-optionals. You can zap the boilerplate and add the following code to see the two sides of Optionals in Swift.
In this case, we’re trying to make a new
NSURL object by popping in a string. However, we get something different for each case. For
rightURL we got a
Some result with a
NSURL within. For
wrongURL we instead got
nil. In neither case, did we get a plain
NSURL returned. This is a good thing, as a
Some result will require explicit unwrapping, forcing us to check for
nil values and account for them defensively. Let’s see how this works in practice.
Everybody Wants Some
If we look at the
NSURL constructor in XCode, we see the following:
That question mark
init tells us that when constructed,
NSURL is going to return an
Optional. In Swift,
Optional is an actual type, specifically a generic enum, that can either hold another object within, or be
nil. Lets checkout what
Optional looks like under the hood:
Here we see that the
Optional enum has two cases,
Some for the generic type specified. In Swift, we can make anything an
Optional.Some by boxing it up:
On the other hand,
None is equivalent for
nil, which you can see here:
In this way, you can think of
Optional as a box, which may or may not contain the object that you specify. By sending a box to a method or function instead of its unwrapped contents, the compiler forces you to open the box and inspect what’s inside. If the box is empty, then you can catch the error and do something about it.
What are Generics?
In statically typed languages, Generics are types that can hold other arbitrary types. Going along with our box example, imagine how a shipper would want generic containers to hold their customer’s contents, but label them based on the content type within (e.g. fragile, perishable, hazardous, etc…). Making a new container for each type would be unnecessarily costly, and that’s no different in statically typed programming languages. Generics allow us to have similar container/label convenience in our code and reap the benefits of reuse.
Swift will implicitly infer the type of new variables and constants for you, which is a nice thing. But to make things more transparent, let’s explicitly set the generic types for our variables in two different (but equal) ways.
rightURL we used the long form way of using the
Optional generic enum with a
NSURL label. As
Optional is a type we will use a lot, Swift gives us the shorthand form of just appending a
? to the end of the type, just like our
NSURL initializer we talked about before. What happens if we try to gundeck our type by not adding a
? at the end?
Trying to skip out on using an
Optional gives us a compiler error with some interesting advice “Value of optional type ‘NSURL?’ not unwrapped; did you mean to use ‘!’ or ‘?’”. We know what the
? does in our code, but what about the exclamation mark
!? Let’s check that out.
Implicit vs Explicit Optionals
? at the end of our type specifies an explicit
Optional. Let’s instead end it with an
! and see what happens:
Here we seem to be getting back an
NSURL without a
Some wrapper, but that is only half of the story. Using
! makes our
implicitURL just as much of an
rightURL. Just as Swift has implicit type inference, it also has implicit
Optional unwrapping. This type, called
ImplicitlyUnwrappedOptional responds just like a normal
Optional, but the Swift complier will automatically unwrap it for you when used. This implicit unwrapping can make
ImplicitlyUnwrappedOptional types a bit more dangerous as you don’t need to explicitly deal with
nil values. But it can help bridge the gap when using legacy Objective-C interfaces that may initially have a
nil value, but will always set it automatically when an application built.
We should now have four different Optional URLs to unwrap and work with, in review:
Let’s Check This Out
One way to check out the existence of an
Optional is to explicitly see if it is
nil. Add the following below our current code and let’s see what we get.
Well, were getting there, but
Optional(http://www.reactive.io) is not what we wanted. If we do have something in our
Optional, how do we get it out? This is where the
! symbol starts to pull double duty. For any
Optional object, an
! appended on the variable or constant name will force it to become unwrapped, and raise an error if it is
nil. Let’s give that a try:
There we go, we are now handling our
Optional unwrapping in a very safe way, but there is another way by using an
if let block. Give the following a try:
Here, we are setting the
url constant to an unwrapped
NSURL value, only if there happens to be one in our
Optional. If not, we have our default. Now, try switching
explicitURL and notice what happens. When we were dealt a
nil, our program does not crash and instead tells us there is no URL to print. Furthermore,
ImplicitlyUnwrappedOptional values act just like our explicit
Optional values, making them interchangeable.
If you wanted to ditch
if conditions, you can also use Swift’s
switch statement as well:
switch statements are still too verbose, we can also use the nil-coalescing operator
?? to further catch
nil values in our code and set sensible defaults. Take a look at this:
If we can be sure that our
rightURL will always have a correct
NSURL (i.e. by hard-coding it), this can be an easy way to assign variables that you can be sure are not
Have Some Class
Now that we’ve worked with
Optional types procedurally, its time to see how we can use them to build object oriented code. Go ahead and replace all the code in our playground with the following:
Notice in our
Box class, the
sender property is an
ImplicitlyUnwrappedOptional, and the
recipient property an
Optional. If you try to make either a plain
String, the Swift compiler will give you an error. This is because these two properties were not set in the initializer, and as such will be
nil for part of an objects lifecycle. For this example, Alice has a book boxed up and ready to send, but does not yet know who to send it to. The Swift compiler might be a bit overzealous in this example as this code immediately sets
alice right after a new
Book object is constructed. But, when not set during initialization,
Optional types are in fact non-optional. Cases like this can make the
ImplicitlyUnwrappedOptional a good choice, as the compiler will be happy with getting an
Optional, and you can treat it as either a plain type or an
Optional one in your code.
Method Call Me, Maybe?
If we want to get the
description of Box’s
recipient, we might run into some trouble. This is because we cannot call a
description method on
nil, and risk raising an error if we force unwrap an
!. Also, conditional statements using
else might be too verbose for one off method calls. This is where Swift gives us another tool by using the
? operator for Optional Chaining. Here, we check the existence of an property before calling a method on it. Let’s give it a go by adding the following below our
Good to go, we got right to calling our
description method, but only if it was there. Furthermore, we got an
Optional in return, which we can then use later. Optional Chaining also works great when we want to call methods that mutate their receiver, but only if there is something to mutate. Lets Add Bob as a recipient now and see what happens.
Here, we are setting our
recipient to a new
Person, in this case Bob. Good news is that both
ImplicitlyUnwrappedOptional types can infer what you need, making the
Optional constructor unnecessary, and our new call can look like this:
Hope Bob gets a good read out of it!
We went through a lot, but got to the core parts of what Optionals are in Swift, and how they make your code more reliable. We also dug deeper into how Optionals can be used both explicitly and implicitly, which will help as you to use them in your code, and in the many libraries that will utilize them. All together, the different ways Optionals can be used will keep you coding faster, while having more fun and less run-time frustration!