---
title: "Mutable value types are evil! Sort of..."
description: "You might have heard that mutable value types are evil. But why is that and why does the .NET framework use them then? Are they really that *evil*?\n\nLet's have a look at a few examples and have a look what is going on!"
updated: 2022-11-06
tags: ["C#", "Value Types", ".NET", "struct"]
canonical: "https://steven-giesel.com/blogPost/7b896127-41a4-4008-87cb-d2fbdd5a0d5b/mutable-value-types-are-evil-sort-of"
---

# Mutable value types are evil! Sort of...

You might have heard that mutable value types are evil. But why is that and why does the .NET framework use them then? Are they really that *evil*?

Let's have a look at a few examples and have a look at what is going on!

Value types are objects, which behave like a single value. Let's take `DateTime` for example. `DateTime` itself acts like an atomic value even though it might consist of multiple parts. `Guid` would be another example of a value type. And all of them have a typical behavior: They are **immutable**. **Immutable** means that the state of the object can not change anymore. Once it's set, it will keep that state virtually forever. You can see that with `DateTime` pretty easily, as the APIs will always return a new `DateTime` object:

```csharp
var stevensBirthday = new DateTime(1991, 5, 17);

// This will not change stevensBirthday, but will return a new DateTime instance
var oneYearLater = stevensBirthday.AddYears(1);
```

Pretty straightforward. So what is the issue, if we would allow a mutable value type? Let's have a small example:
```csharp
var mutableDateTime = new MutableDateTime(1991, 5, 17);

Mutate(mutableDateTime);
Mutate(mutableDateTime);
Mutate(mutableDateTime);

Console.WriteLine(mutableDateTime);

void Mutate(MutableDateTime mutableDateTime) => mutableDateTime.AddOneYear();

struct MutableDateTime
{
    private DateTime internalDateTime;
    
    public MutableDateTime(int year, int month, int day) 
        => internalDateTime = new DateTime(year, month, day);
    
    public void AddOneYear() => internalDateTime = internalDateTime.AddYears(1);

    public override string ToString() => internalDateTime.ToString();
}
```

We create a date time object with the same date as above. We also have a `Mutate` function, which will increase the year by one. Now what is the expected outcome? Something along 1994, because we called the method 3 times? Well no, it is still 1991. The problem is that value types (`struct`) are passed by value (hence the name) so each time we get a copy and not the "original" object. Mutations are only reflected in the copy!

We can make this work, if we pass them by reference:
```csharp
Mutate(ref mutableDateTime);
Mutate(ref mutableDateTime);
Mutate(ref mutableDateTime);

Console.WriteLine(mutableDateTime);

void Mutate(ref MutableDateTime mutableDateTime) => mutableDateTime.AddOneYear();
```

The same applies to storing mutable value types in lists:
```csharp
var list = new List<MyPointX> { new() };
list[0].X = 20;

public struct MyPointX
{
    public int X;
}
```

The compiler will complain about that code with: "*[CS1612] Cannot modify the return value of 'List<MyPointX>.this[int]' because it is not a variable*".

## Why is .NET using them then?
The simple reason is often times: **Performance**. Have a look at `List<T>`, especially the way it returns `GetEnumerator`:
```csharp
public Enumerator GetEnumerator() => new Enumerator(this);
```

The type is implemented as follows:
```csharp
public struct Enumerator : IEnumerator<T>, IEnumerator
```

What is going on here? The reason is very simple: We try to avoid boxing in `foreach` loops. Also cleaning up the stack is super-cheap<sup>of small objects</sup> in comparison to allocating and de-allocating stuff on the heap, plus no Garbage Collector involved. The downside of this is, that the enumerator has to be mutable. I mean you would like to have also the second element in a foreach loop and not only the first one over and over again. Another thing is, that enumerators shouldn't be passed around in the first place. The >80% case is used in some loops and that is it!

Another thing is **caching**. `struct`s are better suited for caching than a `class` object. [Here](https://www.jacksondunstan.com/articles/3399) is some more information about that.

## The compiler can help you
To avoid mutable struct's you can use the `readonly` modifier, which "detects" mutations. This keyword is also allowed with record struct's: `readonly record MyStruct`.

## Conclusion
We saw some pitfalls and reasons to use them. So the bottom line is: Prefer **immutable** value types over **mutable** ones. But in the end, there are certain use cases where they are preferred.
