switch
Picture a sorting machine at a post office. A parcel rides along a belt, the machine reads the number on its label and drops the parcel into one of several chutes. Above each chute hangs a sign: which numbers go there. The last chute is marked "everything else". The machine is not switched on until every number has a chute.
The else if chain from the previous lesson also sorts values into branches, but each branch compares the same value all over again. The switch statement works like the sorting machine: it takes the value once and runs the case branch with the matching sign:
let minutes = 450
let hour = minutes / 60
switch hour {
case 6, 7, 8:
print("breakfast") // breakfast
case 12, 13:
print("lunch")
case 18, 19, 20:
print("dinner")
default:
print("snack")
}Let's walk through the program:
hourgets450 / 60. Dividing whole numbers drops the remainder, sohouris7: 450 minutes after midnight is 7:30.switch hourtakes the value7and checks it against the branches from top to bottom.case 6, 7, 8:— seven is in the list, so the program printsbreakfast.- The program skips the remaining branches,
defaultincluded.
case branches
A branch starts with the word case, followed by its sign and a colon. The branch's code goes under the colon and needs no braces. This lesson covers two kinds of signs.
Several values
Values are listed with commas: case 6, 7, 8:. The branch runs if the value equals any of them. The values have the same type as the expression after switch, here Int.
A range
Instead of a long list, you can write a range with ... or ..<:
switch hour {
case 6...9:
print("breakfast") // breakfast
case 12...14:
print("lunch")
case 18...21:
print("dinner")
default:
print("snack")
}The branch case 6...9: runs for any hour from 6 to 9 inclusive. Values and ranges can be mixed even within one branch: case 0, 22...23:.
default and an exhaustive switch
The default branch runs when no case fits. It is the "everything else" chute.
In Swift a switch must be exhaustive: every possible value must have a branch. The compiler checks this before the program runs, and it checks the type, not the current value. It does not check whether Int values and ranges cover every number, so branches with them never count as complete—not even case Int.min...Int.max:. That is why a switch on a number almost always ends with a default branch, and without one it does not compile:
switch hour { // ✗
case 6...9:
print("breakfast")
case 12...14:
print("lunch")
}error: switch must be exhaustiveUnder the error line, the compiler prints the hint add a default clause, which means "add a default branch".
Only the first matching branch
The machine drops a parcel into the first chute that fits and moves straight on to the next parcel. A switch does the same: it checks the branches from top to bottom, runs the first one that fits and stops there. It does not check the branches below.
Here the post-office picture is not exact. At a real post office a number has exactly one chute, while ranges in a switch can overlap, and then the order of the branches decides. In the program below, the age 15 fits both 7...17 and 15...25. Press "Next step" and watch where the program goes after it prints child:
1let year = 20262let born = 20113let age = year - born4switch age {5case 0...6:6 print("free")7case 7...17:8 print("child")9case 15...25:10 print("student")11default:12 print("adult")13}14print("done")
The constant year gets the value 2026.
After the case 7...17 branch, the program goes straight to the line after the switch. The branch 15...25 does not run, even though 15 is in it. The compiler does not forbid such overlaps, so the order of the branches is your choice.
In C and languages like it, execution at the end of a branch falls through into the next one unless you write break. Swift has no such thing: a branch ends on its own, and no break is needed at its end.
Interviewers like to ask this: how does a switch in Swift differ from one in C? A good answer names three differences:
- a branch does not fall through into the next one, and no
breakis needed at its end; - a
switchis exhaustive: without a branch for every possible value it does not compile; - one
casecan list several values or hold a range.
Common mistake
The program has nothing to do at night, so the branch for the hours 0...5 was left empty:
switch hour {
case 0...5: // ✗
case 6...9:
print("breakfast")
default:
print("snack")
}error: 'case' label in a 'switch' must have at least one executable statementIn Swift a branch cannot be empty: it needs at least one statement. To make a branch do nothing, you write break in it: this statement ends the switch at once. The result is case 0...5: break.
Key points
- A
switchtakes the value once and runs the firstcasebranch it fits: by a list of values or by a range. - After a branch the
switchends on its own: execution does not fall into the next branch, and nobreakis needed. - A
switchis exhaustive: the compiler does not check whetherIntvalues and ranges cover every number, so withoutdefaultsuch aswitchdoes not compile. - An empty branch does not compile; a branch that does nothing is written with
break.