Swift Functions

Write reusable functions with parameters and return types, use argument labels to make calls read like sentences, and add default values, variadic parameters, inout and tuple returns.

Lesson 8 of 43Beginner18 min read

A function packages a piece of work under a name so you can run it whenever you need it, instead of repeating the same lines in several places. Fixing a bug or changing behaviour then happens in one place, and well-named functions make code read like a list of steps.

Swift functions have a distinctive feature: argument labels. When you call a function, each argument is labelled, so calls read like sentences: greet(person: "Ada", from: "London") or move(from: a, to: b). This makes code remarkably self-explanatory, and it's a big part of Swift's style.

In this lesson you'll declare functions with parameters and return values, design clear argument labels, give parameters default values, accept any number of values, return several values at once, let a function change a variable with inout, and store functions in variables.

Declaring and calling functions

Swift
func greet(name: String) {
    print("Hello, \(name)!")
}

func area(width: Double, height: Double) -> Double {
    return width * height
}

greet(name: "Ada")
let room = area(width: 4, height: 3.5)
  • func declares a function; each parameter has a name and a type.
  • -> Double declares the return type, and return sends the result back.
  • A function that returns nothing has no arrow (its return type is Void).
  • When the body is a single expression, return can be left out: func double(_ n: Int) -> Int { n * 2 }.
  • Parameters are constants inside the function; you can't reassign them.

Argument labels

Each parameter can have two names: an argument label used when calling, and a parameter name used inside the function:

Swift
func move(from start: String, to end: String) {
    print("Moving from \(start) to \(end)")
}
move(from: "Leeds", to: "York")

Write _ as the label to call without one, which suits functions where the meaning is obvious: func square(_ n: Int) -> Int, called as square(4). Good labels make the call site read naturally: insert(item, at: 0) or remove(at: 2).

Defaults, variadic parameters and tuples

  • Default values make parameters optional: func order(_ item: String, size: String = "medium") can be called as order("tea") or order("tea", size: "large").
  • A variadic parameter accepts any number of values with ...: func average(_ numbers: Double...), called as average(4, 8, 9). Inside, numbers is an array.
  • Return a tuple to send back several values: func minMax(_ xs: [Int]) -> (min: Int, max: Int), then let r = minMax(scores); r.max.

inout and functions as values

Normally a function receives a copy of each argument. An inout parameter lets it change the caller's variable; the caller writes &:

Swift
func addBonus(to score: inout Int) { score += 10 }
var points = 50
addBonus(to: &points)       // points is now 60

Functions are also values with types like (Int, Int) -> Int. You can store them in variables and pass them to other functions, which leads directly to the closures lesson.

Overloading and a function's full name

Two functions can share a name as long as their parameter labels or types differ. This is called overloading, and Swift picks the right one from the call:

Swift
func area(side: Double) -> Double { side * side }
func area(width: Double, height: Double) -> Double { width * height }

print(area(side: 3))                 // 9.0
print(area(width: 2, height: 5))     // 10.0

Because labels are part of the identity, Swift documentation writes a function's full name with its labels: area(side:) and area(width:height:). You can use that full name to refer to one function without calling it: let calculate = area(width:height:), then calculate(3, 4) gives 12.0. Notice that a stored function is called without labels.

Returning an optional when there may be no answer

Some functions can't always produce a result. Rather than inventing a fake value such as -1, return an optional and send back nil when there's nothing to give:

Swift
func firstEven(in numbers: [Int]) -> Int? {
    for n in numbers where n % 2 == 0 {
        return n                     // leaves the function straight away
    }
    return nil
}
print(firstEven(in: [1, 3, 4]) ?? 0)   // 4

The Int? return type tells every caller that the answer might be missing, and the compiler makes them deal with it. This is the same pattern the standard library uses for Int("42") and array.first.

Swift Functions Syntax

Function forms

func name(param: Type) -> ReturnType { return value }
func square(_ n: Int) -> Int { n * n }
func move(from a: String, to b: String) { }
func order(_ item: String, size: String = "medium") { }
func average(_ xs: Double...) -> Double { }
func minMax(_ xs: [Int]) -> (min: Int, max: Int) { }
func bump(_ n: inout Int) { n += 1 }
bump(&value)

Swift Functions Summary

  • func name(label param: Type) -> ReturnType { } declares a function.
  • Argument labels make calls readable; _ removes a label.
  • Single-expression functions can omit return; parameters are constants.
  • Default values, variadic parameters (Type...) and tuple returns make functions flexible.
  • inout lets a function change the caller's variable, passed with &.

Swift Functions Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Functions with labels and return values

Swift
func celsiusToFahrenheit(_ c: Double) -> Double {
    c * 9 / 5 + 32
}

func describe(temperature c: Double) -> String {
    let f = celsiusToFahrenheit(c)
    let note = c <= 0 ? " (freezing)" : ""
    return "\(c)°C is \(f)°F\(note)"
}

print(describe(temperature: 20))
print(describe(temperature: -5))
Output
20.0°C is 68.0°F
-5.0°C is 23.0°F (freezing)
Line-by-line explanation
  1. Lines 1 to 3A single-expression function with no argument label, so it's called as celsiusToFahrenheit(c).
  2. Line 5The label temperature is used by callers; c is used inside.
  3. Line 11The integer literal 20 becomes a Double because the parameter is a Double.
Example 2

Defaults and variadic parameters

Swift
func formatPrice(_ amount: Double, currency: String = "£") -> String {
    let pence = Int((amount * 100).rounded())
    return "\(currency)\(pence / 100).\(pence % 100 < 10 ? "0" : "")\(pence % 100)"
}

func average(_ scores: Int...) -> Double {
    if scores.isEmpty { return 0 }
    return Double(scores.reduce(0, +)) / Double(scores.count)
}

print(formatPrice(5.5))
print(formatPrice(12.05, currency: "$"))
print(average(70, 85, 90))
print(average())
Output
£5.50
$12.05
81.66666666666667
0.0
Line-by-line explanation
  1. Line 1currency has a default, so it can be left out.
  2. Lines 2 to 3Work in whole pence, then build the text: 550 pence becomes 5 and 50.
  3. Line 6Int... accepts any number of Ints, arriving as an array.
  4. Line 8reduce(0, +) adds every score, as the closures lesson explains.
Example 3

Tuple returns and inout

Swift
func minMax(_ values: [Int]) -> (lowest: Int, highest: Int)? {
    guard let first = values.first else { return nil }
    var low = first, high = first
    for v in values {
        low = min(low, v)
        high = max(high, v)
    }
    return (low, high)
}

func applyDiscount(to price: inout Double, percent: Double) {
    price -= price * percent / 100
}

if let range = minMax([62, 91, 75, 48]) {
    print("Lowest \(range.lowest), highest \(range.highest)")
}

var price = 80.0
applyDiscount(to: &price, percent: 25)
print(price)
Output
Lowest 48, highest 91
60.0
Line-by-line explanation
  1. Line 1The function returns an optional tuple, because an empty array has no minimum.
  2. Lines 11 to 13inout lets the function change the caller's variable.
  3. Line 20& marks the argument as something the function may change.

Common Swift Functions Mistakes

Leaving out argument labels

Don't
func greet(name: String) { print("Hi \(name)") }
greet("Ada")                     // error: missing argument label 'name:'
Do
greet(name: "Ada")
// or declare it as func greet(_ name: String)

Changing a parameter

Don't
func double(_ n: Int) -> Int {
    n *= 2                       // error: left side of mutating operator isn't mutable
    return n
}
Do
func double(_ n: Int) -> Int { n * 2 }

Forgetting & for inout

Don't
addBonus(to: points)             // error: passing value of type 'Int' to an inout parameter requires explicit '&'
Do
addBonus(to: &points)

Swift Functions in Real Projects

Functions in Swift apps

Apple's own frameworks are designed around readable argument labels: view.addSubview(button), array.insert(item, at: 0), string.replacingOccurrences(of: "a", with: "b"). Following the same style in your own code makes it feel natural alongside the system APIs, and small, well-named functions are the building blocks of every SwiftUI view and model.

Swift Functions FAQ

What does the underscore before a parameter name mean in Swift?

_ removes the argument label, so callers pass the value without a name. func square(_ n: Int) is called as square(4) instead of square(n: 4). Use it when the function name already makes the argument's meaning obvious.

What is the difference between an argument label and a parameter name?

The argument label is used at the call site, and the parameter name is used inside the function body. In func move(from start: String), callers write move(from: "Leeds") while the body refers to start. If you write only one name, it's used for both.

How do I return multiple values from a Swift function?

Return a tuple, ideally with named parts: func minMax(_ xs: [Int]) -> (min: Int, max: Int). The caller reads result.min and result.max, or unpacks it with let (low, high) = minMax(scores). For more than a few values, a struct is clearer.

Why can't I change a parameter inside a Swift function?

Parameters are constants, which stops a function from quietly changing values the caller relies on. Copy it into a var if you need a working variable, or mark the parameter inout and call with & if you want the caller's variable to change.

What does "result of call is unused" mean in Swift?

Swift warns when you call a function that returns a value and then ignore the result, because that often signals a bug. Assign it to _ with _ = save() to show you meant to ignore it, or mark the function @discardableResult if ignoring the result is normal.

Swift Functions Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the declaration so the function can be called as square(4).

func square( n: Int) -> Int { n * n }
Predict the outputeasy

What does this print?

func greet(_ name: String = "friend") -> String { "Hi, \(name)" }
print(greet())
Predict the outputmedium

What does this print?

func total(_ xs: Int...) -> Int { xs.reduce(0, +) }
print(total(1, 2, 3, 4))
Multiple choicemedium

How do you call func move(from start: String, to end: String)?

Multiple choicehard

What does an inout parameter allow?

Swift Functions Quiz

5 questions to check what you learned.

  1. Which keyword declares a function in Swift?

    • function
    • func
    • fun
    • def
  2. What does -> introduce in a function declaration?

    • A parameter
    • The return type
    • A label
    • A comment
  3. What is an argument label?

    • The function's name
    • The parameter's type
    • The name callers write before an argument, like from: in move(from: a)
    • A comment
  4. When can a function leave out the return keyword?

    • Never
    • When it returns Void
    • When it has no parameters
    • When its body is a single expression
  5. Can you assign a new value to a normal parameter inside a function?

    • No, parameters are constants; copy them to a var or use inout
    • Yes
    • Only Ints
    • Only with default values