Skip to content
Theory · Conditions · lesson 4 of 5

Patterns in switch

In the previous lesson, each chute of the sorting machine had a sign with numbers or a range. Sometimes that is not enough: you need a chute for "every number below zero", and those cannot be listed. Then an inspector stands at the chute: the inspector looks at the parcel and decides whether to let it in.

The sign after case is called a pattern: a value either fits it or does not. A list of values and a range are patterns you already know. Here is a branch with an inspector:

SWIFT
let morning = -9
let noon = 1
let average = (morning + noon) / 2
switch average {
case let t where t < 0:
    print("frost \(t)") // frost -4
case 0...15:
    print("cool")
default:
    print("warm")
}

Let's walk through the program:

  1. average gets (-9 + 1) / 2, which is -4.
  2. case let t where t < 0: puts -4 into a new constant t and checks the condition t < 0.
  3. The condition is true, so this branch runs: the program prints frost -4.
  4. The program skips the 0...15 and default branches.

A constant in a pattern and where

The branch case let t where t < 0: has two parts.

case let

The pattern let t fits any value and puts it into a new constant t. This constant is visible only inside its own branch. There you use it like any other constant: in the example it goes into a string through \(t).

where

After where you write a condition of type Bool. The branch runs only if the pattern fits and the condition is true. If the condition is false, the switch moves on to the next branch as if the pattern had not fit.

That is the inspector at the chute: the sign let t lets any parcel through, while where t < 0 lets in only negative numbers.

A switch on a string

A switch works with more than numbers. Its branches can compare a string with strings written in advance:

SWIFT
let command = "stop"
switch command {
case "start":
    print("starting")
case "stop", "pause":
    print("stopping") // stopping
default:
    print("unknown command")
}

What matters about such a switch:

  • a string is compared as a whole and case-sensitively: "Stop" does not fit case "stop";
  • several strings in one branch are listed with commas, like numbers;
  • there are endlessly many strings, so a switch on a String needs default too.

fallthrough

Sometimes falling into the next branch is exactly what you want. Then you write the word fallthrough at the end of a branch:

SWIFT
let role = "editor"
switch role {
case "admin":
    print("delete posts")
    fallthrough
case "editor":
    print("edit posts") // edit posts
    fallthrough
default:
    print("read posts") // read posts
}

Let's see how fallthrough works:

  • fallthrough jumps to the start of the next branch without checking that branch's pattern: with role == "editor" the program prints edit posts and then read posts from default;
  • with "admin" the program would print all three lines, and with any other role only read posts;
  • fallthrough cannot be written in the last branch: there is nowhere to go.

You rarely need fallthrough: several values in one branch are usually enough.

Common mistake

Two branches with where cover every number between them, but default was left out:

SWIFT
switch average { // ✗
case let t where t < 0:
    print("below zero")
case let t where t >= 0:
    print("zero or above")
}
TEXT
error: switch must be exhaustive

A person sees that any number is either below zero or not. The compiler, however, does not compare where conditions with each other and assumes each such branch may fail to fit.

Here the inspector picture is not exact: real inspectors could agree among themselves, while a where condition knows only about its own branch. That is why the last branch is written as default: it takes everything the branches above did not let through.

Key points

  • The pattern let t in a case puts the value into a new constant that is visible only inside the branch.
  • where adds a condition to a branch; the compiler does not compare such conditions with each other, so branches with where do not replace default.
  • A switch on a string compares it as a whole, case-sensitively, and needs default too.
  • fallthrough moves into the next branch without checking its pattern.