What the code is supposed to do
The array languages holds three names: "Python", "Java" and "JavaScript". A for loop walks over it and should print one sentence per name:
I think Python is cool!
I think Java is cool!
I think JavaScript is cool!
The code you start with runs fine and prints three lines, but every line says the same thing:
I think language is cool!
I think language is cool!
I think language is cool!
The loop repeats correctly. The problem is in the text it prints.
What goes wrong
Here is the starting code:
val languages = arrayOf("Python", "Java", "JavaScript")
for (language in languages) {
println("I think language is cool!")
}
On each pass, for (language in languages) stores the next element of the array in the loop variable language. On the first pass it holds "Python", on the second "Java", on the third "JavaScript".
The body never looks at that variable. Inside double quotes, language is just six letters of text, exactly like is and cool. A string literal is copied to the output character by character, so the same text is printed on every pass. The variable changes, and nothing reads it.
String templates
Kotlin lets you put a variable's value inside a string with a string template. A dollar sign followed by a name is replaced by that variable's value when the string is built:
val name = "Ana"
println("Hello, $name!") // Hello, Ana!
When you need more than a bare name, such as an expression or a property, wrap it in braces: "${languages.size} languages". For a plain variable like language, $language is enough.
Fixing it step by step
- Leave the array and the loop header alone.
for (language in languages)already visits every element in order and names the current onelanguage. - Find the part of the message that must change on every pass. Only the language name differs from line to line. The words around it stay the same.
- Replace the word
languagein the message with$language. The text is now built from the current element each time, so the three passes print three different lines.
The fixed code in Kotlin
val languages = arrayOf("Python", "Java", "JavaScript")
for (language in languages) {
println("I think $language is cool!")
}
/* Explanation:
Notice that in the original code we didn't actually use the loop variable "language" inside the println() statement.
And so on each iteration, the println() printed "I think language is cool!" no matter if language = "Python" or language = "Java" etc.
The fix is to use the loop variable "language" with string templates to dynamically construct the message:
for (language in languages) {
println("I think $language is cool!")
}
*/
The comment block at the end is only an explanation and does nothing when the program runs. The fix is the single changed line inside the loop. A few Kotlin details are worth knowing:
- The template stops at the end of the name. In
"I think $language is cool!"the space afterlanguageends the variable name. If a letter or digit followed directly, as in"$languages", Kotlin would look for a variable calledlanguagesinstead, which here is the whole array. - A bare
$is a template only when a name follows. To print a literal dollar sign before a name, write\$. The text"cost: \$language"printscost: $language. - No type is needed in the loop header. Kotlin knows that each element of an
Array<String>is aString. - The loop variable is read-only. You can use
languageinside the loop, but you can't assign a new value to it.
Common mistakes
- Forgetting the dollar sign.
"I think language is cool!"compiles and runs, which makes this bug easy to miss. The compiler has no way to know that you meant the variable. - Using string concatenation incorrectly.
"I think " + language + " is cool!"also works and gives the same output, but templates are shorter and are the usual Kotlin style. - Printing the array instead of the element.
println("I think $languages is cool!")uses the whole array. Printing an array with a template shows a type name and a hash code, beginning[Ljava.lang.String;@, instead of the elements, so always use the loop variable. - Changing the loop. The loop is correct. Rewriting it risks breaking the number of passes.
Checking your fix
Run the fixed code in the editor above. It should print exactly the three lines from the start of this page, with Python, Java and JavaScript in that order, followed by nothing else.