Get up to 80 % extra points for free! More info:

Lesson 6 - Type system: Optionals in Swift

In the previous exercise, Solved tasks for Swift lesson 5, we've practiced our knowledge from previous lessons.

Now we're going to finally explain the concept of Optionals, which is very important in Swift. We'll talk about what all the exclamation marks in source code mean. We've already stumbled across a few, and although it may be a little complex concept to start with, it's better to understand at least a little bit what it's all about.

The nil value concept

Programming languages must somehow deal with a situation where a variable has no value. We often encounter this problem with functions which hasn't been executed properly. For example, if a number couldn't be retrieved from the console, the output shouldn't be a number but rather an "empty" value. If Swift returned the 0 or -1 value in this case, we wouldn't be sure whether the number indicates it wasn't possible to read it or the user had entered 0 or` -1. For this purpose, a special `nil value was introduced, which safely indicates that a variable is empty. In other languages, this value is often called null and works the same way.

If we create a standard variable in Swift, we can't assign the nil value to it:

// This code won't work
var number = 15
number = nil // This line will cause an error

That's because someone may not be expecting nil there. In order to assign nil to a variable, we must declare the variable as Optional first.

Optionals

An Optional type can be seen as kind of a box that wraps an ordinary variable. The box always exists, but when opened, the value is either there or it's empty.

Question mark

We create an Optional type by writing a question mark ? after a variable's data type. Let's try it:

var maybeNumber: Int? = 15
maybeNumber = nil

The code was compiled successfully and the maybeNumber variable is now empty, even though it's a number. That sounds good, right?

There's however a problem that a lot of other programming languages failed to deal with. We shouldn't be able to work with the maybeNumber variable as with a normal variable. If we wrote:

var maybeNumber: Int? = 15
maybeNumber = nil
print(maybeNumber * 2)

and the program would be compiled, it could cause a runtime crash in the case of maybeNumber being empty. Of course, we can't multiply "empty" by two. If we tried to write such a program, you'd find that it won't compile. Similarly, Swift wouldn't let us access a method or property of an Optional type. You can try yourself that the following code won't compile because of printing the second string's length:

var s1 = "Hello"
var s2: String? = "World"
print(s1.count)
print(s2.count)

You've probably guessed that Swift doesn't belong to languages that can't deal with this problem :)

Null safety

The mechanism checking how we use the Optional type during the compilation is called null safety. There are several ways to use an Optional variable. Let's try them out one by one.

Exclamation mark

An Optional can be created other way as well. We'll use an exclamation mark !:

var alwaysNumber : Int!
// We can write print(alwaysNumber + 1) but the application will crash, because there's no number in the alwaysNumber box yet

This way we tell Swift that we'll take care of the variable by ourselves and ensure that it has a valid value before accessing it (in this case any integer). In our code, we can work with it as it was a normal initialized Int variable, but the program can easily crash.

You surely figured out that an exclamation mark in a code means a risk and we should rather avoid it.

Opening the box

Now we'll finally learn how to access the values and why we wrote exclamation marks in our code.

The ! operator

Let's start with the most silly one which we've been already using in this course, so that the amount of information wasn't that overwhelming. Using the !! operator we can degrade Swift to the level of older languages such as e.g. Java and bypass the null safety checking. Everything will work unless the variable is nil:

var maybeNumber: Int? = 15
print(maybeNumber! * 2)

The output:

30

This is called force unwrapping.

If it's empty though, the whole application will crash:

var maybeNumber: Int? = 15
maybeNumber = nil
println(maybeNumber! * 2)

We wouldn't even notice this error during compilation. This approach is very uncommon and is used generally in cases when we know that there's always gonna be a value or that the absence of the value is critical enough to terminate the code.

Optional binding

We should always access Optionals carefully through optional binding. We can use two basic structures: the traditional if condition or the guard keyword. There are mainly semantic differences between them (they have different meaning). Let's have a look at them first and then explain what they mean.

Securing Optional values using a condition
var optionalNumber : Int? = 5
if let number = optionalNumber {
    print(number * 2)
} else {
    print("The number is empty")
}

The code in the condition will be executed only if there's a value stored in the optionalNumber variable. The value will then be saved into the number constant; we can work with it as if it was a traditional Int variable so we're not restricted anymore.

By the way, you can use if var as well but since the given variable is accessible only in the block, it doesn't make much sense to modify it anyway.

Guard

In short, we could say that guard works as the opposite and executes the code only if the condition isn't true. In functions, which we can't declare yet, we'll use it to exit the block using the return keyword. We'll show it further in the course.

Opening the box using the default value

Let's show one more way to get rid of an Optional and get the traditional data type. We can easily specify the default value which will be used if an Optional is empty. It's called nil coalescing and it has its own operator, ??.

var maybeNumber: Int?
maybeNumber = nil

let definitellyNumber = maybeNumber ?? 4

print(definitellyNumber)

You can see that the ?? operator is binary, so it requires values on both sides. If the left side isn't nil (empty Optional), the operator just returns this value. Otherwise, if it's nil, it returns the second value.

Here, 4 will be printed because the maybeNumber variable is nil. This is useful in cases when we can easily continue using some default value which we'll set via ??. It's possible to chain this operator but I suggest you don't to keep the code readable.

In the next lesson, Arrays in Swift, we'll talk about arrays.


 

Previous article
Solved tasks for Swift lesson 5
All articles in this section
Swift Basic Constructs
Skip article
(not recommended)
Arrays in Swift
Article has been written for you by Filip Němeček
Avatar
User rating:
1 votes
Activities