Skip to content

Optionals ​

In Tic-Tac-Toe, you used the readLine function to read input from the terminal:

swift
let input = readLine()!

The exclamation point (!) in this code indicates that readLine returns an optional. This chapter explains what optionals are and how you can use them safely.

Optional types and values ​

Swift requires that you initialize all constants and variables before using them. This is an important safety feature. Once initialized, constants and variables always hold a value. If you need to represent the absence of a value, you need an optional.

An optional wraps an existing value and appends a question mark (?) to the type. For example:

swift
var code: Int?
var error: String?

Here, code is an optional Int (an Int?) and error is an optional String (a String?).

The values you can assign to an optional are either the values of the wrapped type or the special literal nil, which indicates the absence of a value:

swift
code = nil
code = -1

error = nil
error = "something went wrong"

You can only assign nil to optionals; regular types don’t allow this.

Optionals start out as nil and can be assigned nil at any point in their lifetime. Consequently, you can’t use an optional where a regular value is expected:

swift
print("Error: " + error)  

This code is invalid because the string concatenation operator (+) requires a value of type String. It doesn’t allow a String?, as that may contain nil.

You must unwrap an optional if you want to use its value. The following sections explain how you can do that.

Optional binding ​

The safest way to unwrap an optional is to use optional binding, which is a special control flow condition. Here’s an example:

swift
if let input = readLine() {
  print(input)
} else {
  print("No input available.")
}

In this example, let input = readLine() is the optional binding. Here’s how this binding works:

  1. The return type of readLine is String?. The function returns either the next line of input or nil if it reaches the end of its input.
  2. The binding attempts to unwrap this String? and assign its value to a local constant input.
  3. The type of input is String. It holds an unwrapped value, not an optional.
  4. If readLine returns a String, the binding succeeds, and the if statement executes its body. Inside this body, you can access the unwrapped value input.
  5. If readLine returns nil, the binding fails, and the if statement executes its else clause instead.

Optional binding isn’t exclusive to the if statement; other control flow statements support it too. Here’s an example that uses optional binding in a while statement:

swift
while let input = readLine() {
  print(input)
}

This code prints out each line of input it reads. The loop stops when readLine reaches the end of its input and returns nil.

Multiple bindings ​

You can unwrap multiple optionals in a single statement by using a comma to separate the bindings. For example:

swift
if let input = readLine(), let number = Int(input) {
  print(number)
}

Recall from Tic-Tac-Toe that you use Int(_:) to convert a string to an integer. This function has a return type of Int? and returns nil if it can’t perform the conversion. The binding let number = Int(input) unwraps this optional. If the input was an integer, the binding succeeds, and the number is printed.

This example also shows that you can use unwrapped values in subsequent conditions β€” the second binding uses input, which was declared in the first binding.

Mixed conditions ​

You can use optional binding and Boolean conditions in the same statement, again using a comma as a separator:

swift
if let code = code, code < 0, let error = error {
  print("Encountered error \(code): \(error).")
}

This example checks if a negative code is set, and if so, prints an error message.

The example also shows the common practice of unwrapping an optional into a constant with the same name. Recall from Control Flow and Booleans that a local constant or variable can shadow an existing constant or variable of the same name. That’s what’s happening here. In the body of the if statement, code and error refer to the unwrapped constants, not to the optionals declared earlier.

In fact, this is so common that Swift has a shorthand for it:

swift
if let code, code < 0, let error {
  print("Encountered error \(code): \(error).")
}

Here, the compiler assumes that code and error unwrap optionals of the same name, and it completes the bindings for you.

Forced unwrapping ​

When you’re sure an optional is not nil, you can use the force-unwrap operator (!) to unwrap it:

swift
let input = readLine()!

This unwraps the String? returned by readLine and assigns it to input.

The force-unwrap operator is a unary postfix operator. You write it after an optional value to unwrap that value. This is how you can tell the force-unwrap operator from the Boolean NOT operator, which is a prefix operator.

Be careful when using the force-unwrap operator. If you force-unwrap an optional that is nil, your program will crash. Therefore, you should only use this operator when you expect the optional to have a value, and nil can only be the result of a programming error. In this case, a crash is acceptable as it helps you detect and fix the error before you ship the program to your users.

In the case of readLine, you should only force-unwrap input you receive from the terminal. When reading from a file, always use optional binding.

Note

The user can type Ctrl+D (on macOS and Linux) or Ctrl+Z (on Windows) at the terminal to send an end-of-file signal, which will cause readLine to return nil. However, this also disconnects your program from the terminal, so there is little you can do to protect against it. In this case, it’s better to crash and inform the user that something went wrong than to silently ignore the error and leave the user typing at a disconnected terminal.

Nil-coalescing operator ​

The nil-coalescing operator (??) safely unwraps an optional by replacing nil with a default value. For example:

swift
var number = Int(input) ?? 0

This code unwraps the return value of Int(input) and assigns it to number. If Int(input) returns nil, the code assigns a default value of 0 instead.

The nil-coalescing operator is a shorthand for a longer expression that uses the ternary operator (?:):

swift
var number = Int(input) != nil ? Int(input)! : 0

Both expressions are equivalent, but the one that uses the nil-coalescing operator is much easier to read and understand.

Up next ​

This chapter covered the basics of using optionals. You’ll continue learning about optionals in Wrapping Up, where you’ll explore some of their advanced features. But first, practice the basics by solving the upcoming exercises.