Problem overview
The program loops over an array of three languages and should print one tailored sentence for each:
I think Python is cool!
I think Java is cool!
I think JavaScript is cool!
The buggy version prints the same line three times, with the word language where the name should be:
I think language is cool!
I think language is cool!
I think language is cool!
The loop itself works: it runs exactly three times. What is wrong is the message it prints.
Why the output is wrong
The loop header declares a variable called language:
foreach (string language in languages) {
Console.WriteLine("I think language is cool!");
}
On each pass, foreach stores the next array element in language: first "Python", then "Java", then "JavaScript". But the call to Console.WriteLine never reads that variable. Everything between double quotes is a string literal, so the word language inside the quotes is just five letters of fixed text. The compiler doesn't look inside a string literal for variable names, and the same text is printed every time.
A variable name only means "the value stored here" when it appears outside quotes.
Step by step
- Split the message at the part that changes. The text
I thinkand the textis cool!are the same on every pass. Only the language name varies. - Put the loop variable between the two fixed pieces. Close the first string after
I thinkwith a space, add+ language +, then open a new string that starts with a space beforeis cool!. - Check the spaces. The spaces next to the variable have to live inside the string pieces, because
+joins strings without adding anything between them.
The solution in C#
string[] languages = {"Python", "Java", "JavaScript"};
foreach (string language in languages) {
Console.WriteLine("I think " + language + " is cool!");
}
Each time through the loop, "I think " + language + " is cool!" builds a new string out of the three pieces, and Console.WriteLine prints it followed by a line break. Running it gives the three expected lines.
Other ways to build the string
C# also has string interpolation. Put a $ before the opening quote and write the variable in braces:
Console.WriteLine($"I think {language} is cool!");
This prints exactly the same text, and many C# programmers prefer it because the sentence reads in one piece. The lesson uses +, which is worth knowing too, since you will see both in real code.
Tracing the fixed loop
A quick trace shows why the fix works. Before each pass, foreach copies the next element into language, and the expression in WriteLine reads whatever is stored there at that moment:
| Pass | Value of language | Text printed |
|---|---|---|
| 1 | "Python" | I think Python is cool! |
| 2 | "Java" | I think Java is cool! |
| 3 | "JavaScript" | I think JavaScript is cool! |
The same trace applies to any array. If you add a fourth name to languages, the loop prints a fourth line without any other change, because the loop body never mentions a specific language.
Edge cases and common mistakes
- An empty array. If
languageshad no elements, the loop body would never run and nothing would print. That is correct behaviour, not a bug. - Variable name inside quotes. This is the bug in the lesson. If the output shows your variable's name instead of its value, look for a variable you typed between quotes.
- A non-string element. If the array held numbers instead,
"Item " + numberwould still work, because+converts the number to text when one side is a string. - Missing spaces.
"I think" + language + "is cool!"printsI thinkPythonis cool!. Keep the spaces inside the string pieces. - Quoting the variable by accident when you add
+."I think " + "language" + " is cool!"compiles and still prints the wordlanguage. The quotes are the problem, not the plus signs. - Changing the loop variable. You can read
languageas often as you like, but C# doesn't let you assign to aforeachvariable. The compiler reports error CS1656.