Swift Programming For Complete Beginners Part 5:

Conditional Logic

Posted 9/23/2018.

You can find Part 4 here.

A programmer's wife tells him to go to the store and get a loaf of bread. As he's leaving, she says "if they have eggs, get a dozen". The programmer comes back with 12 loaves of bread.

A programmer's husband tells her to go to the store and says, "while you're there buy a dozen eggs". She never comes back.

Programming is all about telling a computer what decisions to make in every situation it will encounter when running our programs. These famous computer science jokes illustrate how computers "think" differently from humans. Computers take the instructions we give them literally.

In the first joke, the programmer goes to the store. He's been told to get a loaf of bread. However, if the store sells eggs, he's been told to get "a dozen". The store does sell eggs! So he gets a dozen loaves of bread. The programmer's wife didn't tell him to get a dozen eggs. Without that instruction he reasoned that he should get 12 of the item he had been told to buy instead of 1.

In the second joke, the programmer's husband tells her to go to the store. She's been told to buy a dozen eggs while she's there. She buys a dozen eggs. Now she's still at the store. So she buys a dozen eggs. She's still at the store. So she...you get the point.

In this tutorial we'll see how to write conditional logic in Swift.

If Statements

The "if" statement is the most basic type of conditional logic. We all know how this works. "If this, then that".

Let's create a new Xcode Command Line Tool project called "ConditionalLogic". For a review on how to create Xcode projects, see Part 1.

Replace everything in main.swift with the following:

import Foundation

let x = 4

if x > 3 {
    print("x is greater than 3")
}

If we run this program, the console will print "x is greater than 3" because we've set x to 4.

In Part 3 on types, we learned about boolean values, which are either true or false. When using if statements, the condition must always evaluate to true or false. In this example, "x" is either greater than 3 or it's not. It wouldn't make sense for a condition to evaluate to any other type. We would never say if "hello" or if 3. Our condition could be a complicated expression or a call to a function that returns a Bool, but at the end of the day it always evaluates to true or false.

Now change x to "2" and run the program again. This time the console doesn't print anything. We haven't told the computer what to do when the condition is false. To fix this we can use the else keyword and add the following:

if x > 3 {
    print("x is greater than 3")
} else {
    print("x is less than or equal to 3")
}

If we run the program with x set to "2", the console will now print "x is less than or equal to 3".

We can also write an else if statement in the middle to add another condition:

if x > 3 {
    print("x is greater than 3")
} else if x == 3 {
    print("x is exactly 3")
} else {
    print("x is less than 3")
}

If we set x to 3 and run the program again, the console will print "x is exactly 3". Note that "==" is how we check whether two values are equal to each other, while one equal sign is how we set a constant or variable.

Let's turn the joke from earlier into code:

let doesStoreSellEggs = true
var loavesOfBreadToBuy = 1
if doesStoreSellEggs {
    loavesOfBreadToBuy = 12
}
print(loavesOfBreadToBuy)

Since the condition is true, the variable loavesOfBreadToBuy is set to 12 and the console prints 12.

The Ternary Conditional Operator

We've already been working with operators. "+", "-", "*", and "/" are the arithmetic operators for addition, subtraction, multiplication, and division respectively. We use "=", called the "assignment operator", every time we assign a value to a constant or variable. We use "==", called the "equal to operator", to check if two values are equal.

The ternary conditional operator is a more concise way to write simple boolean logic like we've seen so far. Let's rewrite our two examples from above using the ternary conditional operator:

let messageToPrint = (x > 3) ? "x is greater than 3" : "x is less than or equal to 3"
print(messageToPrint)

Here we're declaring a constant messageToPrint. The ternary conditional operator starts with the condition (x > 3). We use the question mark to define what should happen if the condition is true and a colon to define what should happen when the condition is false.

You can read this line just as you would an if statement. If x > 3, set the constant messageToPrint to "x is greater than 3". Otherwise (else), set messageToPrint to "x is less than or equal to 3". Right now "x" is set to 3, so the console will print "x is less than or equal to 3".

Now let's rewrite our other example.

let doesStoreSellEggs = true
let loavesOfBreadToBuy = doesStoreSellEggs ? 12 : 1
print(loavesOfBreadToBuy)

This version is much more concise. Using the ternary conditional operator, we can also make loavesOfBreadToBuy a constant instead of a variable. As we saw in Part 2 on constants and variables, using a constant when we can makes our code clearer and helps us avoid unexpected behavior.

Switch Statements

What if our logic has many conditions that need to be checked one after the other? For example, let's say we want to write a function that tells us the nearest major city for a given airport code (e.g. JFK -> "New York"). We could write a series of if, else if and else statements as follows:

let airportCode = "JFK"
func nearestCity(toAirportWithCode airportCode: String) -> String {
    if airportCode == "JFK" {
        return "New York"
    } else if airportCode == "PEK" {
        return "Beijing"
    } else if airportCode == "NBO" {
        return "Nairobi"
    } else if airportCode == "LHR" {
        return "London"
    } else if airportCode == "EZE" {
        return "Buenos Aires"
    } else {
        return "Unknown"
    }
}
print(nearestCity(toAirportWithCode: airportCode))

This works and will print "New York", but it's not very concise. We have to repeat if airportCode == on every other line. Using switch statements we can make this code cleaner and easier to read.

Switch statements check a value and define a set of cases to match against. That's what we want here. We have an airport code that could be any String value. We want to check the code against the airport codes we know to look up the nearest major city. Let's rewrite our function using a switch statement.

Replace the nearestCity function with the following:

let airportCode = "JFK"
func nearestCity(toAirportWithCode airportCode: String) -> String {
    switch airportCode {
    case "JFK":
        return "New York"
    case "PEK":
        return "Beijing"
    case "NBO":
        return "Nairobi"
    case "LHR":
        return "London"
    case "EZE":
        return "Buenos Aires"
    default:
        return "Unknown"
    }
}
print(nearestCity(toAirportWithCode: airportCode))

Much better. Here we use the keyword switch before the value we are checking, airportCode, which is a parameter of our function. We use the case keyword before each possible value for which we know the nearest major city. In the body of the case, we return the value for the nearest major city from our function.

At the bottom we use the default keyword to define what happens when airportCode doesn't match any other case. We need this because airportCode could be any String value. For example, we could call our function with the airport code "SFO". Our function isn't checking for that airport code so it doesn't know to return "San Francisco". We could even call our function with "Hello, World!", which of course isn't an airport code.

Review Questions

You should now be able to answer these questions: