Why Immutable

The first question I’d like to answer is "What does "immutable" actually mean?" The dictionary definition is "unchanging over time or unable to be changed". I believe it comes from the root mutate. Which means to change.

Mutation in C#

In C# we modify things all the time. Usually through setter properties on objects. That is exactly the context of this blog post. If you are building a C# application, you typically don’t think twice about creating auto properties on public classes so as to allow any caller to modify then internal state of an object. Why that in itself is often a lazy and bad practice, I don’t really blame C# developer for this. There are tons of examples of classes that demonstrate this bad practice. I won’t go into that now.

Let’s start with a simple example of a car. For this lets assume its a toy car, it has an on switch, and off switch, and a button that makes it move if its on. Lets assume there are two boys playing with the car. The first boy, Jacob for this example, starts to play with the car and he turns it on so it he can make it move. While Jacob has his back turned the other boy, Ryan for this example, turns the car off. When Jacob comes back he presses the button to move the car and is sad that it doesn’t move. He doesn’t know what happened, he knows he turned the car on a few seconds ago.

This is an example of concurrency issue, and also an issue of mutable data. When data is mutable, you have no real guarantees about what the state of the data will be at any given time. You can verify its state before operating on it, but sometimes, it can change between the time you verify the state and you operate on it. Typically in C# this is handled by placing a lock on the object before attempting your operation then releasing the lock. If the data you were working with were immutable, meaning it couldn’t change, then you would have an absolute guarantee that after you check its state it won’t change on you.

In C# the only way that I can think of to make an objects properties immutable is to make them read only. This means that those properties can only be set during the construction of the object. Lets see what that might look like with the toy car example.

public class ImmutableToyCar
{
    private readonly bool isOn; 
    
    public bool IsOn 
    {
        get 
        {
            return isOn;
        }
    }
    
    public ImmutableToyCar(bool turnOn)
    {
        isOn = turnOn;
    }
    
    public void Move()
    {
        if(this.isOn)
        {
            //code to move the car. 
        }
    }
}

Ok, now that creates a basic ToyCar, but its state is still ambiguous. What if you could tell by looking at the type if it could move or not? Maybe if there was a MoveableToyCar then Jacob wouldn’t have been disappointed.
Lets see what that might look like. We will inherit from ImmutableToyCar to get us started.

public class MovableToyCar: ImmutableToyCar
{
    public MovableToyCar (): base(true)
    {
    
    }
}

Ok, now we know the other possible type of ToyCar is a NonMoveableToyCar so lets create a class to represent that as well.

public class NonMovableToyCar: ImmutableToyCar
{
    public NonMovableToyCar (): base(fasle)
    {
    
    }
}

It is now possible to create each type of car. We should fix up the ImmutableToyCar so that we can’t have an ambiguous ToyCar anymore. We’ll need to make the constructor protected and add a static Create method that can create MoveableToyCars or NonMoveableToyCars.

public class ImmutableToyCar
{
    private readonly bool isOn; 
    
    public bool IsOn 
    {
        get 
        {
            return isOn;
        }
    }
    
    protected ImmutableToyCar(bool turnOn)
    {
        isOn = turnOn;
       
    }

    public static ImmutableToyCar Create(bool isOn)
    {
        if (isOn)
        {
            return new MovableToyCar();
        }
        return new NonMovableToyCar();
    }
    
    public void Move()
    {
        if(this.isOn)
        {
            //code to move the car. 
        }
    }
}

Now when Jacob decides to play with his toy car he can only choose between the MoveableToyCar and the NonMoveableToyCar. If he turns his back for a second, Ryan couldn’t have modified the car. If Ryan did want to be sneaky though perhaps he would find a way to turn the MoveableToyCar into a NonMoveableToyCar.

In essence we have modeled the two different states the ToyCar can be in by giving them their own explicit types. Sometimes you will want to transition from one state to another. Often times the nicest way to do this is to take an existing state and create a new state based on it, instead of mutating state. Let’s see how we could model this with our exisiting code. I’m going to suggest just adding another static function to ImmutableToyCar. Typically I’d probably create a new class maybe called Transitions, but for now this will suffice.

public class ImmutableToyCar
{
    public static NonMoveableToyCar MakeNonMoveable(MoveableToyCar car)
    {
        return new NonMoveableToyCar();
    }
    
    public static MoveableToyCar MakeMoveable(NonMoveableToyCar car)
    {
        return new MoveableToyCar();
    }
    
    //removed code for brevity
}

Notice there are two seperate state transition methods. Also check out their parameters. Each one takes a ToyCar in a particular state and transitions it to the other. If there properties that should come along for the ride of course you could pass them to the constructor of the new type, but in this case we didn’t need to do that. The most importnat thing to note is we are createing a new instance when we do the transition. This guarantees that the car will be in exactly the state that we want it to be in.

We don’t often see this kind of code written in C#. We typically mutate state by simply setting properties. This kind of pattern can take a lot of memory since you ar constantly creating new objects, which means memory allocations, but it is a very concurrency safe approach to state mutation.

Now that we have seen how to do this in C# lets do the same exercise in F#.

Mutation in F#

We don’t need the ImmutableToyCar in this example. Also we don’t need classes per se. We will just use record types.

module car =
    type ToyCar = {IsOn:bool}

    type ToyCarType = 
        | Movable of ToyCar
        | NonMovable of ToyCar

    let createCar (x:bool) : ToyCarType = 
        match x with 
        | true -> Movable {IsOn = x}
        | false -> NonMovable {IsOn = x}
    
    let transition (x:ToyCarType) : ToyCarType = 
        match x with 
        | Movable x -> NonMovable {x with IsOn = false}
        | NonMovable x -> Movable {x with IsOn = true}

With that simple module we can guarantee the car is immutable and the type will represent the state of the car. Ryan will no longer be able to fool Jacob when he looks away.

The createCar function either returns a Movable toy car or a NonMovableToyCar. They are completely separate types and cannot be interchanged. It is possible to swap one for another, but since they are different types, its easy to tell the difference. The compiler won’t even let you swap one for another.

Spread The Word
Adam.Wright
 

Adam Wright is a technologist specializing in software development using Microsoft technologies.

Click Here to Leave a Comment Below 0 comments