Skip to content

What it is, what it is for and how to use it

22 mayo, 2021

In these years in which functional languages ​​are beginning to become real alternatives in almost all areas, one of the concepts that is usually associated with them is that of immutability.

While is true that immutability is an idea that is not unique to functional programming, it does become vitally important in this type of language.

Functional programming is based on many mathematical concepts that require immutability to remain valid.

Still, I think it is a concept that is interesting to understand regardless of the type of programming paradigm you use.


Immutability makes our code much more predictable, because we are more aware of where state changes occur.

What is immutability?

The idea is very simple to understand: something is immutable when it cannot be modified.

In the context of programming, a variable is immutable when its value cannot be modified. And an object is when its state cannot be updated after the creation of the object.

It is therefore a way to ensure that our object is not modified in unexpected places, thereby affecting the execution of our program.

Where does immutability apply?

Immutability greatly simplifies the treatment of concurrency

Outside of purely functional programming, where he already commented that his need is stricter, immutability can save us a lot of headaches.

Let’s imagine for example that we are working in Java, and we have a class with this form:


public class Person {
    public String name;
    public String surname;

    public Person(String name, String surname) {
        this.name = name;
        this.surname = surname;
    }    
}

Although in Java they would use getters Y setters Normally, we can leave it that way for simplicity.

If now at any point in the application we have a function that uses an object of type Person, it can be modified from within it without any problem:


public void doSomething(Person person) {
    person.name = "";    
}

In such a simple example it may not make sense, and there are even ways to minimize problems with strict rules about when an object can and cannot be modified.

But in the end the option is there, and when the programs get big and the rush appears, you end up committing violations of those rules.

At a point where it generates many advantages is in multi-threaded applications, where immutability greatly simplifies the concurrency treatment. If something cannot be modified, it does not matter if it is accessed from different threads at the same time, as well as the order in which it is done.

Immutability, in general, makes our code much more predictable, because we are more aware of where state changes occur.

How is immutability achieved?

As the Java API is not immutable, any use we make of it is liable to violate immutability

In the languages ​​prepared for it, it is quite simple, since the syntax itself simplifies the task a lot. In languages ​​like Scala we can make a variable immutable just by using val instead of var to declare it:


val p = new Person("name", "surname")

In Java it is not much more complicated either. It is simply add the word final to what we want to do immutable. If, for example, we want to make the class Person immutable, we would only have to do the following:


public final class Person {
    public final String name;
    public final String surname;

    public Person(String name, String surname) {
        this.name = name;
        this.surname = surname;
    }    
}

In this way, we can already be sure that the state of this object will not change. A little more verbose, but simple right?

Problems arise when we encounter more complex situations. Since the Java API is not immutable, any use we make of it is liable to violate immutability.

Let’s say, for example, that the person keeps a list of people who are his children:


public final class Person {
    public final String name;
    public final String surname;
    public final List children;

    public Person(String name, String surname, List children) {
        this.name = name;
        this.surname = surname;
        this.children = children;
    }    
}

As much as we make the list immutable, its state is mutable, so we can do:


person.children.add(new Person("n1", "s1"));

With which again we have the same problem. There are many ways to fix this, like doing children private and allow access to your children by a method, use the unmodifiable collections from the SDK or any library that offers immutable collections like Guava. Or just use an array.

In short, if you want to make sure that something is immutable, you have to be sure that the states of the objects that that class uses for its own state are also immutable.

How do you modify the state in an immutable environment?

You may be asking yourself this question. If everything is immutable, there are no state changes, and therefore the program will do nothing.

The way to modify an immutable object is to simply copy it by modifying the necessary values. Again, languages ​​that pay attention to immutability have mechanisms to make this simple. For example if we have a data class in Kotlin:


data class Person(val name: String, val surname: String)

Language already provides us with a function copy who will do the hard work for us:


val p1 = Person("p1", "s1")
val p2 = p1.copy(surname = "s2")

In Java it would be a bit more complex, but it doesn’t have much history either:


Person p1 = new Person("p1", "s1");
Person p2 = new Person(p1.name, "s2");

Immutable lists work the same. If we add an element to a list, we are actually returned another list that has all the objects from the previous one plus the new one.

Is it always worth using immutability?

If you are developing with the object-oriented paradigm, there are times that surely is not worth it. Immutability has the extra cost of generating new objects every time the state changes, so this can seriously penalize performance.

As a very general guide, it is advisable to use mutable objects in the following cases:

  • For objects with very large states, when copying an object can take considerable execution time.
  • Objects that need to be built little by little, because we can’t get the whole state at once.
  • Maintain running state

And in general, any situation that requires a state that is modified often and / or the duplication of that state is costly.

Immutability, on the other hand, has advantages in the following situations:

  • On objects that will not require state modifications
  • Objects that are simple to duplicate, even if they are modified sporadically
  • In concurrent situations

As I mentioned before, immutability makes the code much more predictable and easier to test, because we narrow down the places where state modifications occur much more.

So a simple rule can be to make as much code as possible immutable.

Conclusions.

Immutability is a very powerful concept that can help us to simplify the complexity of understanding our code and, therefore, to reduce the chances of unexpected errors.

Although in object-oriented programming it is not as essential as in functional programming, it is interesting to know this idea to apply it where it may seem most useful to us.

Did you know this concept? Do you use it regularly? And if not, do you find it interesting to apply it in your day to day?