Flow Control

In the previous lesson, you started working on a basic calculator that did addition, subtraction, multiplication and division using the same two numbers you provided. No real calculators ever do that! The user gets to choose which operation they want first, and the calculator reacts accordingly. The execution of the calculator changes based on the input you provide. This is what flow control means.

Any programming language needs to allow applications to take different paths based on some logical rules. Swift provides a variety of ways to do this.

if Statement

The first of those ways you’ll learn about are if and else. They’re as easy as they sound. Take this real life example:

If the weather is sunny
  I'll go out for a walk
else
  I'll watch a movie

This is a simple decision based on if the state of the weather being sunny is true. If the weather was not sunny, or weather being sunny is false — then watch a movie.

This is how it works in Swift:

if CONDITION {
  THINGS_TO_DO_IF_CONDITION_IS_TRUE
} else {
  THINGS_TO_DO_IF_CONDITION_IS_FALSE
}

The structure for an if statement is:

  1. The if keyword, followed by a condition that resolves to true or false.
  2. Followed by a code block. A code block is one or more lines of code surrounded by curly brackets { }.
  3. Optionally, you can add else after the code block to do something if the condition in the if before it was false. You can always skip the else if it isn’t needed in the logic you’re writing:
if weather == "raining" {
  takeUmbrella()
}

goToTheOffice()

This example has no else. You’re going to the office anyway, but before doing that, you check if the weather equals to "raining" and if so, take the umbrella. If it’s not "raining", don’t do anything special.

You might be wondering if it has to be only two options? The answer would be no, it’s not limited to only two options. You can chain multiple if conditions together with elses in between:

if weather == "raining" {
  takeUmbrella()
} else if weather == "snowing" {
  takeHeavyFuryCoat()
} else if weather == "windy" {
  takeLightCoat()
} else if weather == "sunny" {
  takeCap()
}

if day == "workday" {
  goToTheOffice()
} else {
  goToTheClub()
}

This code consists of two sets of if conditions. The first is about the weather, and the second is about the day of the week.

The first set starts by checking if the weather is raining; if it isn’t, then it checks if it’s snowing, then windy, then sunny. They are checked in order, and once one of them succeeds, all of the following conditions are skipped and the execution moves to the second set, which deals with the day of the week.

The weather can be raining and windy, but because the check for raining comes first, the code block for raining executes first and the code blocks for windy and any of the other else conditions is not checked. If your code needs to consider all the possibilities, where more than one condition may be true, then don’t connect them with else:

if weather == "raining" {
  takeUmbrella()
} 
if weather == "snowing" {
  takeHeavyFuryCoat()
} 
if weather == "windy" {
  takeLightCoat()
} 
if weather == "sunny" {
  takeCap()
}

Notice there is no else at the very end of the weather checking part. If none of the four conditions is true, nothing special will happen.

The second condition, about the day of the week, executes no matter what happened with the weather checking. If the day is a workday, then go to the office, otherwise go to the club. It doesn’t check if it’s a holiday that the club might be closed or any special conditions like that. So it could happen that you go to the club and find it closed, showing your logic to decide where to go is faulty. In computer terms, it’s called: it had a bug.

The term bug in electronics was first mentioned by Thomas Edison in 1878 while working on an improvement on the telegram system to be able to transmit four telegrams at the same time. He found an actual insect in his experiment that caused it to malfunction. And later in 1947 a moth was found in a computer that caused it to malfunction. The term stuck to computers since the 1947 incident but existed long before then.

Now, bug describes any moment an app behaves unexpectedly or reaches an illogical result.

switch Statement

Another form of flow control is the switch statement. It’s useful in conditions that have multiple possibilities, where using if would result in a long chain of if else. That long chain might become hard to read. Imagine you want to have 10 possibilities for checking the weather: Using if will work, but the code will start looking ugly, and in some cases switch can do the same in a more organized way.

switch isn’t necessarily true or false based. You provide it a variable and different cases for values that can be stored in that variable.

switch (VARIABLE) {
case VALUE_1:
  DoOperation_1()
case VALUE_2:
  DoOperation_2()
case VALUE_3:
  DoOperation_3()
case VALUE_4:
  DoOperation_4()
default:
  FallbackOperation()
}

Each possible value is written with case before it and a colon :after it, followed by whatever code operations you need, and it doesn’t require using curly braces { }.

The one thing you need to note is that a switch needs to be exhaustive. Meaning that it needs to know what to do when any of the values are found and what to do when none is found. Thats why default is mentioned, and something needs to happen there. You can’t leave it empty. So you can always — and I highly recommended doing so — enter a print statement like print("switch didn't find any matches"). This message can go a long way to help you understand what might have gone wrong with your code when your app doesn’t perform what you think it should do.

Converting the earlier weather checks to use switch looks like this:

switch (weather) {
case "raining":
  takeUmbrella()
case "snowing":
  takeHeavyFuryCoat()
case "windy":
  takeLightCoat()
case "sunny":
  takeCap()
default:
  print("Weather is none of the 4 conditions")
}

Something else switch can do is to execute two conditions together using fallthrough. As an example of that: If its snowing, you want to take the heavy fury coat and the umbrella. If it’s just raining, take only the umbrella without the coat. For that, you need to consider the case for snowing before raining and make snowing fallthrough to the raining case to check it, too:

switch (weather) {
case "snowing":
  takeHeavyFuryCoat()
  fallthrough
case "raining":
  takeUmbrella()
case "windy":
  takeLightCoat()
case "sunny":
  takeCap()
default:
  print("Weather is none of the 4 conditions")
}

Writing this using if requires you to change the snowing check like this:

if weather == "snowing" {
  takeHeavyFuryCoat()
  takeUmbrella()
} 

That makes takeUmbrella() execute twice in the code. It’s OK because it’s a single line, but as your code becomes more complex, it will be hard to read. Also, if you change what happens in raining you would also need to repeat the changes for snowing. This duplicates work and adds more effort to maintaining this code in the future.

A final way you can adapt a switch to different logic is to use a compound case.

switch (weather) {
case "snowing", "sleeting":
  takeHeavyFuryCoat()
case "raining":
  takeUmbrella()
case "windy":
  takeLightCoat()
case "sunny":
  takeCap()
default:
  print("Weather is none of the 5 conditions")
}

In this code, if the weather is snowing or sleeting, then takeHeavyFuryCoat() will execute.

In the next demo, you’ll update your calculator from the previous lesson to perform one of the four math operations based on another variable.

See forum comments
Download course materials from Github
Previous: Introduction Next: if & switch Demo