Source code
Best Practices C#

Explaining Mutability and Immutability in C#

Welcome to today’s post.

In today’s post I will be explaining what mutability and immutability is in C#.

Normally I would not be delving into language related features, and one reason is that I’ve been told that, and experienced once that this topic is one commonly raised question during an interview. Another reason is that there is confusion between mutability and immutability and value and reference types. I will clear these confusions with a definition and follow with some examples and rationale.

I will first explain what an immutable type is. I will then explain why some common types are mutable or immutable. I will also show how to make some mutable types immutable. I will also show how immutable and mutable objects differ when assigning objects.

What is an Immutable Type?

An immutable type is a type that satisfies the following conditions:

  1. Its state does not change.
  2. Its instance does not change.
  3. Its properties do not change.

First, I will list the most common immutable and mutable types.

Commonly used immutable types are:

Int
Float
Single
Double
String
DateTime

Commonly used mutable types are:

StringBuilder
List<T>
Dictionary<TKey,TValue>
ConcurrentStack<T>

What makes the String type Immutable?

When we declare an assigned string:

String s = “hi!”;

A string object with the name s, with a value “hi!” is created.

After creation we CANNOT modify the string without having to create a new instance of the string!

When apply a concatenation operation as follows:

s = “hi ” + “there!”;

The original string is no longer the same reference as the concatenated string, so the instance of the variable changes and the starting address of the new string contents are referencing a new pointer address. This means the original string has NOT been modified, it has been re-created. Immutability of the type causes a new instance of the type to be created, the original contents are copied over to the new address of the new instance, and the memory for the original string is deallocated. The original string is no more!    

What makes an Int type Immutable?

When we declare an assigned int variable:

int x = 1;

An integer object with the name x, with a value 1 is created.

After creation, can we still modify the integer value without creating a new instance of the variable x?

No.

Why?

When we try the following:

x += 1;

As we have with the string type, a new instance is created for variable x, the modified value is copied across to the new instance, and the memory allocated for the original variable is deallocated. The resulting variable with a value of 2 will be a new instance. Essentially the increment is achieved is two steps:

temp = x + 1;
x = temp + 1;

What if most value types like int and string were mutable?

If this were the case, then if we were running our code within a multi-threaded process and the same variable as shown was being modified by two or more threads concurrently:

x += 1;

Then there is the possibility of memory corruption caused by the multiple threads attempting to access and modify a value at the same address space!

For each running thread, a new copy of an immutable variable is made when it is modified. This protects the code from concurrency issues (access violations) but increases the memory usage.

Forcing Immutability to a Value Type Variable

We can force a variable to be immutable read only by using the readonly keyword, as shown:

readonly int x;

A variable declared this way can be modified in the following circumstances:

1. Within the declaration itself, such as the following:

public readonly int x = 1;

2. Within a class constructor, such as the following:

public readonly int _x;

public myClass(int x)
{
	this._x = x;
} 

What makes a StringBuilder class mutable?

With a StringBuilder class we can modify a string within the object instance without having to create a new object instance.

This is quite beneficial when we are adding or modifying many strings within a variable without having to allocate a new section of memory. When a string is created as follows:

StringBuilder myMutableString = new StringBuilder("Hi there!");

And strings are appended:

myMutableString.Append(“Isn’t it a sunny day!”);

What this does is to append the new text to the end of the existing object without allocating a new instance. When the capacity of the StringBuilder is exceeded, the space for the original string will be reallocated and the new text appended to the end of the object. When we set the maximum capacity of a string builder instance, additional strings can be appended to the end of the object without reallocation until the string length reaches MaxCapacity

What makes a List collection mutable?

With a list collection, the common operations of adding and removing from a list modify the internal list structure of the collection without modifying the instance of the list object.

What differs between Mutable and Immutable types when we assign objects?

When we assign two objects that are mutable, such as two different List collections, the reference to the list collection is copied, not the value!

So, in this example:

List<string> X = new List<string>();
List<string> Y = new List<string>();

X.Add(“A”);
Y = X;

foreach (string value in Y)
{
    Console.WriteLine(“Y = ” + value)
}

Y.Add(“B”);

foreach (string value in X)
{
    Console.WriteLine(“X = ” + value)
}

The above code will output the following:

Y = A
X = A
X = B

When a list is assigned to another list, the reference of the other list is assigned, so any changes to the other list are reflected in the original list.

When we assign two objects that are immutable, such as to different strings, a new instance of the target list is copied, not the reference!

So, in this example:

string X = “X”;
string Y = “Y”;
Y = X;

Console.WriteLine(“X =” + X);
Console.WriteLine(“Y =” + Y);

Y = “Z”;

Console.WriteLine(“X =” + X);
Console.WriteLine(“Y =” + Y);

The above code will output the following:

X = X
Y = Y
X = X
Y = Z

When a string (the destination) is assigned to another string (the source), a new instance of the destination string is made, then the contents of the source string are copied across to the destination string’s instance. The destination strings memory is the deallocated. This is what we expect from a string when it is assigned as it is immutable.

Other ways we can make collections Immutable

We can make collections immutable by using the ImmutableList<T> sealed type from the System.Collections.Immutable namespace.

An immutable list has the same operations as a mutable list, the difference being that the operations do not alter references to the list objects, they make copies of the list objects before applying the operation. An immutable list has no public constructor, with all operations resulting in a new object instance. Immutable collections are thread safe and suitable for multi-threaded scenarios. The structure and state of immutable objects are preserved when passed as parameters, making them better suited for testing.

Other ways we can make classes immutable

A class can be made immutable by using the following methods:

  1. Declare class properties as readonly.
  2. Declare only get accessors.
  3. Declare private get accessors.
  4. Use a constructor to initialize internal properties.

In the example below we create an immutable class that initializes its members through a constructor:

public class MyImmutableClass
{
    public string _A { get; private set; }
    public string _B { get; }

    public Contact(string A, string B)
    {
        A = _A;
        B = _B;
    }
}

Below is the client that is only permitted to read properties of the immutable class:

public class Program
{
    static void Main()
    {
        var immA = select new MyImmutableClass("A", "B");

	Console.WriteLine("{0}, {1}", immA.A, immA.B);
    }
}

There are different pros and cons and benefits with immutable and mutable objects, the main ones being thread safety of immutable objects vs the memory efficiency and testability of mutable objects.

I hope the above has been a useful overview and discussion on the difference between immutable and mutable objects in C#.

That is all for today’s post.

I hope you found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial