Start learning free

LESSON 57 OF 347 · STRINGS I

String Immutability in C#: Why You Can't Assign to message[0]

Lesson Read the full explanation

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

For example, the following code:

string message = "Jello world";

message[0] = 'H';

would produce an error.


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 C# 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:

string message = "Jello world";

message = "Hello world";

Console.WriteLine(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

    C# · STRINGS I

    String Immutability in C#, explained

    What immutable means

    A C# string is immutable: once it has been created, none of its characters can change. Reading a character with an index is fine, but writing to one is not.

    string message = "Jello world";
    
    char first = message[0];  // fine: reading gives 'J'
    message[0] = 'H';         // compile error
    

    The second line does not compile. The indexer on a string is read-only, and the compiler reports that string.this[int] cannot be assigned to.

    The variable can still change

    Immutability applies to the string value, not to the variable that refers to it. A variable can be pointed at a different string at any time:

    string message = "Jello world";
    
    message = "Hello world";
    
    Console.WriteLine(message);  // Hello world
    

    This does not edit the first string. It creates a second string, "Hello world", and makes message refer to it. The old string is left alone, and the runtime discards it later if nothing else uses it.

    Because the old string is untouched, another variable that referred to it keeps its value:

    string a = "abc";
    string b = a;
    
    a += "d";
    
    Console.WriteLine(a);  // abcd
    Console.WriteLine(b);  // abc
    

    Here a += "d" creates a new string and points a at it. The variable b still refers to "abc". This is a big part of why immutability is useful: nobody can change a string out from under you.

    Methods return new strings

    Every method that seems to modify a string actually returns a new one and leaves the original as it was. This is a common source of bugs:

    string word = "hello";
    
    word.ToUpper();               // result thrown away
    Console.WriteLine(word);      // hello
    
    word = word.ToUpper();        // keep the result
    Console.WriteLine(word);      // HELLO
    

    The first call produces "HELLO" and then discards it. If you want the change, assign the result back to a variable. The same goes for Replace, Trim, Substring and the rest.

    Building a changed copy

    To "change" one character, build a new string out of the pieces you want to keep. Substring(1) returns every character except the first, and + joins strings into a new one:

    string word = "jello";
    
    word = "H" + word.Substring(1);
    
    Console.WriteLine(word);  // Hello
    

    When you need to change many characters, creating a new string every time gets wasteful. Then StringBuilder or a char[] is the usual tool, because both can be edited in place:

    using System.Text;
    
    StringBuilder builder = new StringBuilder("jello");
    builder[0] = 'H';
    
    Console.WriteLine(builder.ToString());  // Hello
    

    The StringBuilder is a separate, mutable object. Calling ToString() turns its contents back into an ordinary string.

    Why strings are immutable

    Immutability makes strings safe to share. Many parts of a program can hold the same string without worrying that one of them will change it for the rest. It also lets the runtime reuse identical string literals, and it makes strings dependable as dictionary keys, because a key's contents can never change after it has been stored.

    The cost is that each "change" allocates a new string. For a handful of edits that is nothing to worry about. Inside a loop that appends thousands of times, it adds up, which is when StringBuilder pays off.

    The exercise, step by step

    The lesson starts with a name that has a typo: name holds "bndrei Chiriac", and the fix has to produce "Andrei Chiriac". The starter line, name[0] = 'A';, tries to overwrite the first character, which is not allowed.

    1. Drop the wrong first character. name.Substring(1) returns "ndrei Chiriac", which is the name without its first character.
    2. Put the right one in front. Joining "A" and that result with + gives "Andrei Chiriac".
    3. Assign it back to name. The variable now refers to the corrected string.
    string name = "bndrei Chiriac";
    
    // Change code below:
    
    name = "A" + name.Substring(1);
    

    The "A" is a string in double quotes, so + joins two strings. Single quotes would make it a char, which is a different type. The assignment is also why the code compiles: it gives name a brand new string rather than editing the old one.

    Common mistakes

    • Assigning to an index. name[0] = 'A' never compiles, whatever the value.
    • Ignoring the returned string. Calling name.Substring(1) on its own line changes nothing, because the result is not stored.
    • Mixing up Substring(0) and Substring(1). Substring(0) returns the whole string, so the typo would stay in.

    Key takeaways

    • Strings are immutable: their characters can be read but not assigned.
    • A variable can be reassigned to a new string at any time.
    • String methods return new strings, so store the result if you need it.
    • To change part of a string, build a new one from pieces with Substring and +.
    Keep going with C#About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free