Functions

9.1 Defining and Calling

func greet(person: String) -> String {
    "Hello, \(person)!"                     // implicit return for single expressions
}
greet(person: "Ana")

func add(_ a: Int, to b: Int) -> Int {      // external label "to", omitted first label with _
    a + b
}
add(2, to: 3)

func log(_ message: String, level: String = "INFO") {   // default parameter
    print("[\(level)] \(message)")
}
log("Started")
log("Failed", level: "ERROR")

func sum(_ numbers: Int...) -> Int { numbers.reduce(0, +) }   // variadic
sum(1, 2, 3)

func minMax(_ array: [Int]) -> (min: Int, max: Int)? {      // multiple return values via a tuple
    guard let first = array.first else { return nil }
    return array.reduce((first, first)) { (min($0.0, $1), max($0.1, $1)) }
}
if let bounds = minMax([3, 9, 1]) { print(bounds.min, bounds.max) }

9.2 inout Parameters

func swapValues(_ a: inout Int, _ b: inout Int) {
    (a, b) = (b, a)
}
var x = 1, y = 2
swapValues(&x, &y)

9.3 Function Types and Higher-Order Functions

func square(_ x: Int) -> Int { x * x }
let operation: (Int) -> Int = square
func apply(_ f: (Int) -> Int, to value: Int) -> Int { f(value) }
apply(square, to: 5)

func makeMultiplier(_ factor: Int) -> (Int) -> Int {
    { $0 * factor }
}
let triple = makeMultiplier(3)
triple(10)   // 30

9.4 Nested Functions, Overloading and Never

func outer() -> Int {
    func helper(_ x: Int) -> Int { x * 2 }   // nested function
    return helper(21)
}

func describe(_ x: Int) -> String { "Int \(x)" }
func describe(_ x: String) -> String { "String \(x)" }   // overloading by type

func crash(_ message: String) -> Never { fatalError(message) }

9.5 Attributes on Functions

@discardableResult (suppresses the unused-result warning), @inlinable/@inline(__always) (performance), @available, @MainActor, @Sendable, @escaping, @autoclosure, rethrows, async, throws(E).