Skip to content
Lesson 8 of 15

Step 1 of 5 · Reading · ~3 min

Learn

Functions and Closures

Functions

A Swift function declares its parameter types and its return type, and the compiler holds you to both.

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

print(area(width: 5, height: 3))

//> 15

func, a name, a parameter list, -> and the return type, then the body. A function that returns nothing simply omits the -> Type.

The thing that surprises everyone: argument labels

Notice the call site above. It is not area(5, 3) — it is area(width: 5, height: 3). Swift requires the labels by default. They are part of the function's identity, not decoration.

Each parameter actually has two names: an argument label used by callers, and a parameter name used inside the body. When you write only one name, it serves as both.

func greet(to person: String) -> String {
    return "Hello, \(person)!"
}

print(greet(to: "Alice"))

//> Hello, Alice!

to is what callers write; person is what the body uses. The call reads like a sentence and the body reads like code — that is the whole point of the split.

Removing the label with _

For a function whose arguments need no explanation, an underscore suppresses the label:

func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}

print(add(3, 4))

//> 7

Does not compile — the label was suppressed but the caller supplied one

func add(_ a: Int, _ b: Int) -> Int { return a + b }
add(a: 3, b: 4)

Compiles

func add(_ a: Int, _ b: Int) -> Int { return a + b }
add(3, 4)

The rule is symmetric and strict: the call site must match the declaration exactly. Deleting an underscore from a signature breaks every existing call.

Default values

Give a parameter a default and callers may skip it:

func greet(name: String, greeting: String = "Hello") -> String {
    return "\(greeting), \(name)!"
}

print(greet(name: "Alice"))
print(greet(name: "Bob", greeting: "Howdy"))

//> Hello, Alice!
//> Howdy, Bob!

Put parameters without defaults first — they are the ones that carry the meaning.

Implicit return

If the body is a single expression, the return keyword is optional:

func double(_ n: Int) -> Int { n * 2 }
print(double(21))

//> 42

This only works for a single expression. A body containing print(...) and nothing else does not implicitly return anything, because print produces no value.

Returning more than one value

A tuple lets a function hand back several values at once, with names:

func minMax(_ xs: [Int]) -> (low: Int, high: Int) {
    return (xs.min()!, xs.max()!)
}

let result = minMax([3, 8, 2])
print(result.low, result.high)

//> 2 8

Functions are values

Every function has a type, written the same way as its signature: add above has type (Int, Int) -> Int. That means a function can be stored in a variable or handed to another function — which is exactly what the next lesson builds on.

let op: (Int, Int) -> Int = add
print(op(10, 5))

//> 15

Your exercise

Fill in func square(_ n: Int) -> Int so it returns n * n, and let the starter's existing print(square(n)) do the rest.

The mistake the grader catches is leaving the placeholder in place. The starter's body is return 0, and because one visible test feeds 0 and expects 0, an untouched starter already passes that one — a partial pass is not progress. The second trap is the underscore: if you retype the signature as func square(n: Int) -> Int, the label comes back and the starter's own square(n) call stops compiling. Change the body, not the signature. A hidden test passes -5 and expects 25, which n * n handles without any special case.

Up nextClosuresFunctions and Closures

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…