Start learning free

LESSON 36 OF 415 · FUNCTIONS I

Function Parameters and Arguments in Swift: Labels and _

Lesson Read the full explanation

So far, the functions we've created execute a fixed task without context / inputs. But most often we want our functions to produce different outcomes depending on the context behind the function call.

For example, it would be nice if sayHello() would print a personalized message such as "Hello humans" or "Hello cats" or "Hello dogs", depending on the audience instead of "Hello world" no matter what.


Function parameters:

Function parameters allow functions to accept input(s) and perform a task using the input(s). We use parameters as placeholders for information that will be passed to the function when it is called.

When a function is defined, its parameters are specified between the parentheses that follow the function name.

Here is our function with one String parameter, audience:

func sayHello(audience: String) {
    print("Hello \(audience)")
}

Calling with arguments:

Then we can call sayHello() and specify the values in the parentheses that follow the function name. The values that are passed to the function when it is called are called arguments.

// Function declaration:
func sayHello(audience: String) {
    print("Hello \(audience)")
}

// Function call:
sayHello(audience: "humans") // Output: Hello humans

We have passed one string argument: "humans". Inside the function audience will equal string "humans" and acts just like a regular variable.


Argument labels & the _ underscore:

Notice that when we call the function we repeat the parameter's name: sayHello(audience: "humans"). That name at the call site is the argument label — by default Swift uses each parameter's name as its label.

If you'd rather call the function without a label, write an underscore _ before the parameter name. The _ means "no argument label":

func sayHello(_ audience: String) {
    print("Hello \(audience)")
}

sayHello("humans") // Output: Hello humans  — no label needed

You'll see this _ throughout the coding tutorials, e.g. func magicNumber(_ n: Int) -> Int, which lets you call magicNumber(1998) instead of magicNumber(n: 1998). Inside the function you still refer to the parameter by its name (audience, n).


Multiple parameters:

A function can have as many parameters as it needs. Here is a function with two parameters:

func sayHello(name: String, age: Int) {
    print("\(name), aged \(age)")
}

// Let's call it:
sayHello(name: "John", age: 30) // Output: John, aged 30
sayHello(name: "Mary", age: 26) // Output: Mary, aged 26

Notice that the order in which arguments are passed and assigned follows the order that the parameters are declared.


Variables as arguments:

Variables can also be passed as arguments for function calls:

func sayHello(name: String, age: Int) {
    print("\(name), aged \(age)")
}

let name = "Andy"
let age = 28

sayHello(name: name, age: age) // Output: Andy, aged 28

sayHello(name: "Mary", age: age) // Output: Mary, aged 28

Parameters are constants:

Inside a function, its parameters are constants (like a let) — you cannot reassign them. This does not compile:

func countdown(_ n: Int) {
    n = n - 1 // error: cannot assign to value: 'n' is a 'let' constant
}

If you need to change the value, make a mutable copy with var. Re-using the same name simply shadows the parameter:

func countdown(_ n: Int) {
    var n = n // a mutable copy you can change
    while n > 0 {
        print(n)
        n -= 1
    }
}

That's why many of the coding tutorials begin a function with a line like var n = n.


Assignment
Follow the Coding Tutorial and let's write some functions.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 5
    Ctrl + Enter to check

    SWIFT · FUNCTIONS I

    Function Parameters And Arguments in Swift, explained

    Why functions take input

    A function with no input does the same thing on every call. Most useful functions need to vary: greet a different person, add different numbers, check a different word. Parameters are the placeholders that make that possible. They are declared in the parentheses of the function definition, each with a name and a type:

    func sayHello(audience: String) {
        print("Hello \(audience)")
    }
    

    Here audience is a parameter of type String. The \(audience) inside the string is string interpolation: Swift replaces it with the value of the expression in the parentheses.

    The values you pass in when you call the function are the arguments:

    sayHello(audience: "humans") // Hello humans
    sayHello(audience: "cats")   // Hello cats
    

    "Parameter" is the name in the definition and "argument" is the value in the call. Inside the body, the parameter acts like an ordinary constant holding the argument.

    Argument labels and the underscore

    Look at the call sayHello(audience: "humans"). The word audience: before the value is an argument label. By default Swift uses the parameter's own name as its label, and a call that leaves it out doesn't compile:

    error: missing argument label 'audience:' in call
    

    If you'd rather call the function without a label, write an underscore before the parameter name. The _ means "no label":

    func sayHello(_ audience: String) {
        print("Hello \(audience)")
    }
    
    sayHello("humans") // Hello humans
    

    Now the reverse is an error, because a label that doesn't exist is rejected too:

    error: extraneous argument label 'audience:' in call
    

    Inside the function you still use the parameter's name, audience. Swift also lets a parameter have a separate label for the call, as in func greet(to person: String), called as greet(to: "Mia") and used inside as person. The lessons mostly use the plain name or _.

    Several parameters

    A function can have as many parameters as it needs, separated by commas:

    func sayHello(name: String, age: Int) {
        print("\(name), aged \(age)")
    }
    
    sayHello(name: "John", age: 30) // John, aged 30
    sayHello(name: "Mary", age: 26) // Mary, aged 26
    

    Arguments must come in the same order as the parameters. Swapping them is a compile error (argument 'name' must precede argument 'age'), and so is passing a value of the wrong type, such as a string where an Int is expected.

    Variables as arguments

    An argument can be any expression of the right type, including a variable or a constant:

    let name = "Andy"
    let age = 28
    
    sayHello(name: name, age: age) // Andy, aged 28
    sayHello(name: "Mary", age: age) // Mary, aged 28
    

    In name: name, the first name is the label and the second is the constant. The function receives the value stored in it.

    Parameters are constants

    Inside the body, a parameter can't be reassigned:

    func countdown(_ n: Int) {
        n = n - 1
    }
    

    This fails with cannot assign to value: 'n' is a 'let' constant. To change the value, make a mutable copy with var, reusing the same name:

    func countdown(_ n: Int) {
        var n = n // a mutable copy
        while n > 0 {
            print(n)
            n -= 1
        }
    }
    
    countdown(3) // prints 3, 2, 1, one per line
    

    The new n shadows the parameter, and the caller's value is untouched. Many later lessons start a function with var n = n for this reason.

    The exercise, step by step

    1. Define welcomeUser above mainFunction, with one String parameter called name. Put _ before the name so callers don't need a label.
    2. Print the greeting with interpolation. For "Andy" it must print Welcome, Andy!.
    3. Call it with a literal from mainFunction: welcomeUser("Andy").
    4. Create a constant name inside mainFunction and set it to "John". It uses let because the value never changes.
    5. Pass the constant to the function: welcomeUser(name).

    The solution in Swift

    func welcomeUser(_ name: String) {
        print("Welcome, \(name)!")
    }
    
    func mainFunction() {
        welcomeUser("Andy")
        let name = "John"
        welcomeUser(name)
    }
    

    Running mainFunction prints:

    Welcome, Andy!
    Welcome, John!
    

    The constant name in mainFunction and the parameter name in welcomeUser are two unrelated names that happen to match. The call copies the value across.

    Common mistakes

    • Forgetting the _, or the label. The definition and the call must agree about whether there is a label.
    • Leaving out the type. Every parameter needs one: name: String.
    • Forgetting the backslash in \(name). Without it, the text (name) is printed literally.
    • Using var for a value that never changes. let says what you mean.
    • Typing the greeting differently. The comma, the space and the exclamation mark are part of the expected output.

    Key takeaways

    • Parameters are the names in the definition. Arguments are the values in the call.
    • By default a call includes each parameter's name as a label. _ removes the label.
    • Arguments are matched by position and must have the right type.
    • Parameters are constants inside the function. Use var n = n to get a copy you can change.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free