Skip to content
Theory · Strings · lesson 5 of 10

Strings are immutable

A printed receipt cannot be corrected. If a price was entered wrong, the cashier does not rub out the digits but prints a new receipt. The old one does not change: you can throw it away or keep it.

Strings in C# are immutable: once a string is created, none of its characters can be changed. Methods such as ToUpper do not edit a string; they create a new one, the way a cashier prints a new receipt. What happens if you forget about the new string?

C#
string name = "anna";
name.ToUpper();
Console.WriteLine(name); // anna
name = name.ToUpper();
Console.WriteLine(name); // ANNA

Let's go through the example line by line:

  1. name.ToUpper(); creates a new string "ANNA", but it is not saved anywhere, so it is lost.
  2. Console.WriteLine(name) prints anna: the original string stayed the same.
  3. name = name.ToUpper(); creates "ANNA" again and this time puts it into the variable name.
  4. Now it prints ANNA.

It is the string that is immutable, not the variable. You can assign a new string to name as many times as you like. You only cannot change the characters inside a string that already exists.

A method returns a new string

Every method that seems to change a string creates a new one and returns it. ToUpper, ToLower, Trim, Replace and Substring all work this way. To keep the result, you assign it: to a new variable or to the same one.

The compiler does not warn when a call's result is lost: the line name.ToUpper(); compiles without a single warning. That is why this mistake often goes unnoticed.

In the widget a string variable, like an array variable, is shown with an arrow: → "cat" means "leads to the string cat". Press "Next step" and watch which string each name leads to after ToUpper and after +=.

LiveA new string instead of the old onestep 1 of 9 · frames: 1

The string cat is created, and a gets a reference to it.

The arrow shows which string the variable leads to

ToUpper never changed the string "cat": the first time its result was lost, the second time it went into c. And += did not add a letter to the old string either: it created a new string "cats" and moved a to it.

Two variables, one string

Like an array variable, a variable of type string holds a reference: string is a reference type. So string b = a; copies the reference, and one string gets two names.

With an array, a write through b would change the shared array, and you would see it through a. With a string that cannot happen: no method edits a string. Every "change" gives a new string, and only the variable it is assigned to moves to it.

This is where the receipt and the string part ways. A paper receipt lies in one hand, while any number of variables can lead to one string. That is safe precisely because nobody can correct the string.

Why strings are immutable

Interviewers often ask this: why is string a reference type that behaves like a value? Because a string cannot be changed: a shared reference to it is as good as a copy of your own. Immutability brings two main benefits:

  • you can pass a string to a method or keep it in several variables, and nobody will change it behind your back;
  • identical literals, such as two "cat"s in one program, are stored by the runtime as one string, which saves memory.

Immutability has a price. Every "change" creates a new string and copies characters into it. One such copy goes unnoticed, but thousands of copies in a loop slow the program down.

Common mistake

Someone tried to replace a character of a string by index:

C#
string word = "cat";
word[0] = 'b'; // ✗
Console.WriteLine(word);
TEXT
error CS0200: Property or indexer 'string.this[int]' cannot be assigned to -- it is read only

The program does not compile. The square brackets of a string work for reading only: you can read word[0] but not write it. The word indexer in the message means exactly this access by index in square brackets. To get bat, build a new string: word = "b" + word.Substring(1);.

Key points

  • A string is immutable: its characters cannot be changed after it is created, and s[0] = 'x' does not compile.
  • String methods return a new string, so s.ToUpper(); without an assignment changes nothing.
  • It is the string that is immutable, not the variable: s = s.ToUpper() puts a new string into s.
  • b = a gives a string a second name, but a += "s" creates a new string, and b still leads to the old one.