Functions and closures

Chapter 4 printed Pack tea and Pack milk inside a loop. When another part of the script needs that wording, give it a name:

func pack(item: String) -> String {
    return "Pack \(item)"
}
func twice(_ count: Int) -> Int {
    return count * 2
}
print(pack(item: "tea"))
print(pack(item: "milk"))
print("Twice: \(twice(3))")
Pack tea
Pack milk
Twice: 6

func defines a function; the parentheses hold its parameters. In pack(item: String), item is the name inside the function and the label at the call. The -> String promises a result, which return sends back. twice(_ count: Int) skips the call-site label with _, so the call is twice(3). Inside, the parameter is still called count.

A parameter cannot be reassigned inside its function. If a calculation needs a changing working value, start a local var from the parameter. That keeps the input name steady while you work.

Leave early

A portion count for zero guests needs no calculation:

func portions(for guests: Int) -> Int {
    guard guests > 0 else {
        return 0
    }
    return guests * 2
}
print("Three guests: \(portions(for: 3))")
print("No guests: \(portions(for: 0))")
Three guests: 6
No guests: 0

The external label for makes the call read portions(for: 3); the function uses guests inside. If there are no guests, the guard takes its required else branch and returns 0. Otherwise execution carries on below the brace. The condition must be a Bool, just as it was for if in chapter 3. The failing branch must leave the function, rather than slipping through to return guests * 2. We’ll meet guard with an optional value in chapter 7; no optional is needed for this check.

A function you can hand over

Functions can take other functions as inputs. apply takes a number and a function to use on it:

func apply(_ number: Int, using transform: (Int) -> Int) -> Int {
    return transform(number)
}
let offset = 2
let addOffset: (Int) -> Int = { number in number + offset }
print("Offset: \(apply(4, using: addOffset))")
print("Double: \(apply(4) { number in number * 2 })")
Offset: 6
Double: 8

(Int) -> Int describes a function that takes one Int and returns one Int. The closure between braces is a value of that type. Because addOffset has a type annotation, number gets its type from the context; in separates the parameter from the calculation. A single-expression closure returns that expression. It can also read offset, the let binding beside it.

The second call puts its final closure after apply(4). Those braces supply an argument; apply calls the closure with its number. The first call uses the same argument position, but passes a named value as using: addOffset. Here offset stays fixed. We’ll leave changing captured variables for later.