What the code should do
The method WelcomeUser takes a person's name and prints a welcome message for that person. MainFunction calls it twice, once for Andy and once for John, so the expected output is:
Welcome, Andy!
Welcome, John!
This time the code compiles and runs, but the output is wrong. Both calls print the same line:
Welcome, Andy!
Welcome, Andy!
This is a different kind of bug from a compiler error. The program does exactly what it was told, and what it was told is not what we meant.
What goes wrong
Here is the starting code:
public void WelcomeUser(string name) {
Console.WriteLine("Welcome, Andy!");
}
public void MainFunction() {
WelcomeUser("Andy");
WelcomeUser("John");
}
The call WelcomeUser("John") does reach the method. The string "John" is stored in the parameter name, and the body runs. But the body never looks at name. It prints a string literal that has Andy typed into it, so every call prints the same text whatever you pass in.
The compiler does not complain about this. An unused parameter is legal C#, and some editors only show a faint hint about it. When a method behaves the same for every argument, check whether it actually reads its parameters.
A parameter is only a placeholder until you use it
A parameter is a variable that receives a value from each call. Declaring it makes the value available, and nothing more. For the value to affect the output, the body has to use the parameter's name in an expression.
The text that never changes, "Welcome, " and "!", stays as fixed strings. The part that changes between calls, the person's name, must come from the variable. The fix is to build the message out of three pieces: fixed text, the variable, fixed text.
Why this bug is easy to miss
If you only ever call WelcomeUser("Andy"), the buggy version prints the right line, so a single test passes. The bug shows up only when a second, different argument is tried. This is why tests use several inputs, and why this lesson calls the method for two different people. When a result looks right for one input, ask yourself whether it would still be right for another, and read the body to see where the input is used, and whether it is used at all.
Fixing it step by step
- Find what differs between calls. Only the name changes. The words
Welcome,and the exclamation mark are the same every time. - Split the string. Cut the literal
"Welcome, Andy!"into the part before the name,"Welcome, ", and the part after it,"!". Note the space after the comma, which belongs to the first piece. - Join the pieces. Put
namebetween them with the+operator, which concatenates strings. - Leave the calls alone.
MainFunctionis already correct, because it passes a different argument each time.
The fixed code in C#
public void WelcomeUser(string name) {
Console.WriteLine("Welcome, " + name + "!");
}
public void 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:
Console.WriteLine("Welcome, " + name + "!");
*/
Now the first call prints Welcome, Andy! and the second prints Welcome, John!. The method still returns nothing: void means it only prints. Two C# details are worth knowing about the fixed line:
- Concatenation with
+. When one side of+is astring, C# joins the two sides into a new string. Strings in C# are immutable, so+never changesname. It builds a new string forWriteLineto print. - String interpolation. The same message can be written as
$"Welcome, {name}!". The$before the opening quote lets you put a variable's value inside curly braces. The result is identical, and many people find it easier to read once there are several variables.
Common mistakes
- Forgetting the space.
"Welcome," + nameprintsWelcome,Andy. The space has to be inside one of the quoted pieces. - Putting the variable inside the quotes.
"Welcome, name!"is just text, so it prints the wordnameevery time. Only a name outside quotes is read as a variable. - Changing the calls instead of the body. Editing
MainFunctioncannot help, because the calls already pass the right values. - Passing the name to
WriteLineas a second argument.Console.WriteLine("Welcome, ", name)compiles, butWriteLinereads its first argument as a format string. It prints onlyWelcome,, with no name at all. Build one string first, then print it. - Hard-coding a value because it works for one test. If a method has a parameter, check that its result changes when the argument changes.
Checking your fix
Run the code in the editor above. The output should be exactly two lines, one for each call, with the correct names. A quick extra test is to add a third call such as WelcomeUser("Sally"). If it prints Welcome, Sally! without any other change to the method, the parameter is doing its job.