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
- Define
welcomeUserabovemainFunction, with oneStringparameter calledname. Put_before the name so callers don't need a label. - Print the greeting with interpolation. For
"Andy"it must printWelcome, Andy!. - Call it with a literal from
mainFunction:welcomeUser("Andy"). - Create a constant
nameinsidemainFunctionand set it to"John". It usesletbecause the value never changes. - 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
varfor a value that never changes.letsays 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 = nto get a copy you can change.
