Strings can't be changed in place
A Scala String is immutable: once created, its characters never change. You can read name(0), but you can't assign to it. This is the code from the lesson:
var name: String = "bndrei Chiriac"
name(0) = 'A'
It doesn't compile. The compiler reports:
value update is not a member of String
In Scala, name(0) = 'A' is shorthand for name.update(0, 'A'). Arrays have an update method, but strings don't, so the compiler rejects the line.
A variable is not the string
Immutability applies to the string value, not to the variable. A var can be pointed at a different string at any time:
var message = "Jello world"
message = "Hello world"
println(message)
Hello world
This doesn't edit "Jello world". It creates a second string, "Hello world", and makes message refer to it. With a val even that is forbidden: val name = "x" followed by name = "y" fails with Reassignment to val name.
The exercise, step by step
The variable holds a name with a typo, and the goal is "Andrei Chiriac":
- Keep the typo's tail. Only the first character is wrong, so
name.substring(1)gives"ndrei Chiriac", everything after index 0. - Build the correct start. Join
"A"and that tail with+. The result is a new string. - Reassign the variable. Because
nameis avar, it can refer to the new string.
var name: String = "bndrei Chiriac"
// Change code below:
name = "A" + name.substring(1)
Afterwards name holds Andrei Chiriac. The old string with the typo is no longer referenced.
Other ways to get a modified copy
Every "change" to a string is really a new string. Besides substring and +, Scala offers:
val typo = "bndrei"
println(typo.updated(0, 'A')) // Andrei
println(typo.patch(0, "A", 1)) // Andrei
println(typo.replace('b', 'A')) // Andrei
updated(index, char) returns a copy with one character replaced. patch(from, text, count) replaces count characters starting at from. replace swaps every occurrence of a character or substring.
Methods like toUpperCase and trim work the same way: they return a new string and leave the original as it was.
Why immutability is useful
- A string you pass to a function can't be changed behind your back.
- Strings can safely be shared, for example as keys in a map.
The cost is that building a long string by repeated + copies characters each time. For many pieces, a StringBuilder is the right tool.
Common mistakes
- Calling a method and ignoring the result.
name.substring(1)on its own line changes nothing. Use the returned value. - Using
valand then reassigning. If the variable will point at new strings, declare it withvar. - Using brackets.
name[0]is not valid Scala; indexing uses parentheses.
Building a string piece by piece
When you assemble text from many parts, a StringBuilder is mutable and avoids copying the whole string on every step:
val sb = new StringBuilder
for (c <- "abc") sb.append(c.toUpper)
sb.append("!")
println(sb.toString) // ABC!
The builder is the changeable object. Calling toString at the end gives you an ordinary immutable string.
Checking that the original is unchanged
You can confirm that a method didn't touch the string by printing both values:
val word = "Hello World"
val upper = word.toUpperCase
println(upper) // HELLO WORLD
println(word) // Hello World
The call produced a second string and left word alone. This is why the lesson's fix has to assign the result somewhere: a new string that nothing refers to is simply discarded.
Key takeaways
- You can't assign to a character of a
String. - A
varcan be reassigned to a new string. - String methods return new strings; the original stays as it was.
