What the code is supposed to do
The function welcomeUser takes a person's name and prints a welcome message for that person. Called for Andy and then for John, it should print:
Welcome, Andy!
Welcome, John!
This code compiles and runs, but it prints Welcome, Andy! twice:
class Solution {
func welcomeUser(_ name: String) {
print("Welcome, Andy!")
}
func mainFunction() {
welcomeUser("Andy")
welcomeUser("John")
}
}
What goes wrong
This bug produces no error message, which makes it harder to spot than a compiler error. Swift can't know that the text inside the quotes was meant to change. The string "Welcome, Andy!" is a fixed piece of text, so every call prints exactly that text.
The function receives its argument in the parameter name, but the body never reads it. The value for John arrives and is dropped. Swift does not warn about an unused function parameter, so nothing flags the problem. The only clue is the output, which repeats the same line.
Fixing it step by step
- Look at the output. Identical lines for different arguments mean the function ignores its input.
- Find the part that should vary. In
"Welcome, Andy!", onlyAndyshould change. The rest,"Welcome, "and"!", stays the same for everyone. - Split the string at that point. Keep the fixed text in quotes and put the parameter
namebetween the two pieces, outside any quotes. - Join the pieces with
+. ForStringvalues,+concatenates: it puts the pieces together with nothing in between, so the spaces and punctuation must be inside the quoted parts.
The fixed code in Swift
class Solution {
func welcomeUser(_ name: String) {
print("Welcome, " + name + "!")
}
func mainFunction() {
welcomeUser("Andy")
welcomeUser("John")
}
}
/* Explanation:
Notice that in the original function we didn't actually use our parameter "name".
And so the function printed "Welcome, Andy!" no matter if we passed "Mike" or "Sally" etc. to it.
The fix is to use the parameter "name" with string concatenation or string formatting to dynamically construct the message:
print("Welcome, " + name + "!")
*/
With the fix, the call for John produces Welcome, John!, and any other name works too.
String interpolation: the other way to do it
Swift also lets you put a value inside a string literal with \(...). This does the same job and is the more common Swift style:
func welcomeUser(_ name: String) {
print("Welcome, \(name)!")
}
welcomeUser("Mike") // Welcome, Mike!
welcomeUser("Sally") // Welcome, Sally!
Inside the parentheses you can use any expression, not only a variable. With interpolation, you don't have to remember to close and reopen the quotes.
Common mistakes
- Putting the name inside the quotes.
print("Welcome, name!")prints the lettersnameliterally, because quoted text is never treated as a variable. - Forgetting the spaces.
"Welcome," + nameprintsWelcome,John. The space after the comma must be inside the string. - Adding a number with
+."Welcome, " + 5doesn't compile, because+joins two strings. Convert it withString(5)or use interpolation. - Changing the calls. The calls in
mainFunctionare correct. The mistake is in the function body.
Checking the fix
Try more than the two names in the lesson. A correct welcomeUser gives these results:
welcomeUser("Mike")printsWelcome, Mike!.welcomeUser("Sally")printsWelcome, Sally!.welcomeUser("")printsWelcome, !, because an empty string is still a validString.
If a name you pass shows up in the output, the function is reading its parameter.
Key takeaways
- A parameter only matters if the body uses it.
- If different arguments give the same output, check whether the function reads its parameters.
- Keep fixed text in quotes and put variables outside them, joined with
+, or use\(name)inside the quotes.
