Start learning free

LESSON 59 OF 414 · STRINGS I

String Immutability in Scala: Why You Can't Edit a Character

Lesson Read the full explanation

In Scala, strings are immutable, which means that they cannot be altered once created.

For example, the following code:

var message = "Jello world"

message(0) = 'H'

would produce a compile error (value update is not a member of String).


Variable can still be changed:

Note that this does not mean that message cannot be changed, just that the individual characters of a string literal cannot be changed.

"Jello world" is a string literal that Scala stores in memory, while message is a variable that refers to that string literal.

When we do message(0) = 'H', we are trying to alter the string literal "Jello world", which is not allowed.

But like any other variable, message can be changed by reassigning it with a new string, like this:

var message = "Jello world"

message = "Hello world"

println(message)

This code would output:

Hello world

Instead of trying to alter the first string, this code now creates a new one ("Hello world"), stores it in memory and tells message to refer to this new string.


Assignment
Follow the Coding Tutorial and let's practice with string immutability!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    SCALA · STRINGS I

    String Immutability in Scala, explained

    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":

    1. Keep the typo's tail. Only the first character is wrong, so name.substring(1) gives "ndrei Chiriac", everything after index 0.
    2. Build the correct start. Join "A" and that tail with +. The result is a new string.
    3. Reassign the variable. Because name is a var, 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 val and then reassigning. If the variable will point at new strings, declare it with var.
    • 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 var can be reassigned to a new string.
    • String methods return new strings; the original stays as it was.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free