Note: this is the first of a short series of short posts on Swift Optional
,
subscribe to the newsletter or RSS
feed to avoid missing out on the next
ones.
Optional values are definitely one of my favourite things about Swift.
I love they how force you to deal with nullability, and how the
compiler never fails to remind when you are not doing so. I
also love that if a value is not optional then I am
guaranteed it is an actual value, and I don't have to worry
about nil
at all.
The Swift team has done a great job at making working with optional values easy and straightforward. Developers can work with optionals without really knowing they're there. This is great to onboard beginners, but I feel that to fully appreciate, and leverage, optionals we need to dig a bit deeper.
Let's have a look at this piece of code for example:
let x: String? = "Hello World"
if let y = x {
print(y)
}
When I started looking into Swift my understanding of this code would have been
something like: "there's a value x
that is a String
that may or may not be
nil. Make sure that x
is not nil, and if so print it".
That is what that code does, right?
The point that I was missing is that x
is not "a String
that may or may not
be nil", but a different type all together.
In fact if you add a print(x.dynamicType)
statement in the code above you'll
see this in the console:
Optional<String>
String?
is actually syntactic sugar for Optional<String>
, and Optional
is
a type in its own right.
Here's a simplified version of the header of Optional
, which
you can see by command-clicking on the word Optional
in your
code from Xcode:
enum Optional<Wrapped> {
/// The absence of a value.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
}
Optional
is actually an enum
, defined in relation to a generic type
Wrapped
. It has two cases: .none
to represent the absence of a value, and
.some
to represent the presence of a value, which is stored as its associated
value of type Wrapped
.
I find the fact that such a powerful tool is implemented in such a simple fashion remarkable and fascinating.
Let me go through it again: String?
is not a String
but an
Optional<String>
, Int?
is not an Int
but an Optional<Int>
, and so on.
Understanding that optional values have a different type explains why we need to check if the actual value is there or not before using it.
One cannot call .length
on an Optional<String>
the same way one cannot call
.legth
on an Int
, the type doesn't have the method. And even if it had it
we would be calling it on the wrong object.
The fact that Optional
is a type means that it has its own methods, for
example map
and flatMap
. If you are curious about what they do check out
this post.
What does "unwrapping optionals" really mean
When describing the if let
example code above, if past me wanted to show off,
it would have said "I unwrap the optional". But let me tell you, he didn't know
what he was talking about.
Fortunately we now have seen that T?
really means Optional<T>
, and the
whole wrapping business now makes more sense.
A value of optional type wraps another type. It can wrap any type, so in its
definition we use a generic, which we can call T
or Wrapped
like the Swift
team has done for extra clarity.
You can imagine Optional
hugging Wrapped
with its angle bracket arms, to
keep it safe from the dangers of nullability.
Now the sentence "I unwrap the optional" makes more sense. Tools like if let
aand guard let
allow us to try to get the actual value out of its Optional
wrapper, and react to the case when its not there.
I hope this post has helped you appreciating Swift's optional values, and
understand what all those ?
really mean. But what about the !
? We'll look
at them in the next post, subscribe to avoid missing out 😉.
Feel free to get in touch with me on Twitter @mokacoding or to leave a comment below if you have any questions or if there's something wrong in the post.
Leave the codebase better than you found it.