The problem: repeated code
Suppose three students each have to write the same apology. Without functions, the program repeats three lines for every student:
print("This is Andy")
print("Andy made a mistake")
print("Andy suffers the consequences")
print("This is Mike")
print("Mike made a mistake")
print("Mike suffers the consequences")
Only the name differs between the blocks. If the wording changes, you must edit every block, and with ten students and a longer apology the program becomes tedious and easy to break.
The fix: a function with a parameter
A parameter is a variable declared in a function's header. An argument is the value you pass for it in a call. Write the shared lines once, with the name as a parameter, and call the function once per student:
func printMessage(name: String) {
print("This is \(name)")
print("\(name) made a mistake")
print("\(name) suffers the consequences")
}
printMessage(name: "Andy")
printMessage(name: "Mike")
printMessage(name: "Sally")
Now a change of wording happens in one place, and a new student is one more call. Inside the string, \(name) is string interpolation: Swift replaces it with the value of name.
Argument labels and the underscore
Swift calls usually name their arguments. In printMessage(name: "Andy") the word name: is an argument label, and leaving it out is an error. Writing an underscore before the parameter removes the label:
func greet(_ name: String) {
print("Hi, " + name)
}
greet("Andy") // Hi, Andy
The lesson's functions use the underscore, so calls pass plain values. The body still uses the name after the underscore.
The lesson's exercise, step by step
- Define the function. Above
mainFunction, writefunc introduceYourself(_ name: String, _ language: String). Each parameter has a type, and both areString. - Print the name. The text
"My name is "ends with a space, because+adds nothing between the pieces. Joining it withnamegives, for example,My name is Andy. - Print the language the same way, with
"I code in ". - Call it for John. Inside
mainFunction,introduceYourself("John", "Python"). Arguments match parameters by position: the first goes toname, the second tolanguage. - Call it for Mary with
"Mary"and"JavaScript". Only the arguments change, not the printing code.
The solution in Swift
func introduceYourself(_ name: String, _ language: String) {
print("My name is " + name)
print("I code in " + language)
}
func mainFunction() {
introduceYourself("John", "Python")
introduceYourself("Mary", "JavaScript")
}
The two calls print:
My name is John
I code in Python
My name is Mary
I code in JavaScript
Common mistakes
- Swapping the arguments.
introduceYourself("Python", "John")compiles, because both are strings, and printsMy name is Python. Swift can't tell which string means what; the order is your responsibility. - Forgetting an argument.
introduceYourself("John")fails with "missing argument for parameter #2 in call". - Passing the wrong type. A call such as
introduceYourself("John", 5)fails because5is anIntand the parameter is aString. - Forgetting the trailing space.
"My name is" + nameprintsMy name isJohn. - Calling with labels after removing them. With the underscores in place,
introduceYourself(name: "John", language: "Python")is an error. Without the underscores, leaving the labels out is the error.
Changing the story
The payoff comes when something changes. To change the students, edit only the arguments in the calls. To change the apology, edit only the function body, and every call follows:
func printMessage(name: String) {
print("This is the apology of \(name)")
print("\(name) made a mistake and so \(name) suffers the consequences")
}
printMessage(name: "Andrei")
printMessage(name: "Paul")
A parameter can appear as many times as you like in the body, as name does in the second line.
Key takeaways
- A parameter lets one function handle many different values.
- Write shared logic once, and vary only the arguments.
- Swift matches arguments to parameters by position and checks their types.
- An underscore before a parameter name removes its argument label.
