In the last post, we learned about Purity, Side effects and Ordering. In this part, let’s talk about immutability and concurrency.

If you haven’t read part 1, please read it here:

Immutability

Immutability is the idea that a value once created can never be modified.

Let’s say I have an Car class like this:

Java

public final class Car {

private String name;



public Car(final String name) {

this.name = name;

}



public void setName(final String name) {

this.name = name;

}



public String getName() {

return name;

}

}

Kotlin

class Car(var name: String?)

Since it has a setter in Java and is a mutable property in Kotlin, I can modify the name of the car after I’ve constructed it:

Java

Car car = new Car("BMW");

car.setName("Audi");

Kotlin

val car = Car("BMW")

car.name = "Audi"

This class is not immutable. It can be modified after creation.

Let’s make it immutable. In order to do that in Java, we have to:

Make the name variable final.

Remove the setter.

Make the class final as well so that another class cannot extend it and modify it’s internals.

Java

public final class Car {

private final String name;



public Car(final String name) {

this.name = name;

}



public String getName() {

return name;

}

}

In Kotlin, we just have to make the name an immutable value.

Kotlin

class Car(val name: String)

Now if someone needs to create a new car, they need to initialize a new object. No one can modify our car once it’s created. This class is now immutable.

But what about the getName() getter in Java or the name accessor in Kotlin? It’s returning our name variable to the outside world right? What if someone were to modify the name value after getting a reference to it from this getter?

In Java, strings are immutable by default. Even if someone got a reference to our name string and were to modify it, they would get a copy of the name string and the original string would remain intact.

But what about things that are not immutable? A list perhaps? Let’s modify the Car class to have a list of people who drive it.

Java

public final class Car {

private final List<String> listOfDrivers;



public Car(final List<String> listOfDrivers) {

this.listOfDrivers = listOfDrivers;

}



public List<String> getListOfDrivers() {

return listOfDrivers;

}

}

In this case, someone can use the getListOfDrivers() method to get a reference to our internal list and modify it thus rendering our class mutable.

To make it immutable, we must pass a deep copy of the list in the getter that is separate from our list so that the new list can be safely modified by the caller. We must also make a deep copy of the list that is passed in to our constructor so that no one can modify it externally after the car is constructed.

A deep copy means that we copy all the dependent data recursively. For instance, if the list was a list of Driver objects instead of just plain strings, we’d have to copy each of the Driver objects too. Otherwise, we’d be making a new list with references to the original Driver objects which could be mutated. In our class, since the list is composed of immutable strings, we can make a deep copy like this:

Java

public final class Car {

private final List<String> listOfDrivers;



public Car(final List<String> listOfDrivers) {

this.listOfDrivers = deepCopy(listOfDrivers);

}



public List<String> getListOfDrivers() {

return deepCopy(listOfDrivers);

}



private List<String> deepCopy(List<String> oldList) {

List<String> newList = new ArrayList<>();

for (String driver : oldList) {

newList.add(driver);

}

return newList;

}

}

Now this class is truly immutable.

In Kotlin, we can simply declare the list immutable in our class definition itself and then it’s safe to use (unless you call it from Java and some other edge cases like that)

Kotlin

class Car(val listOfDrivers: List<String>)

Concurrency

Okay, so immutability is cool and all but why bother? As we talked about in part 1, pure functions allow us easy concurrency and if an object is immutable, it’s very easy to use in pure functions since you can’t modify it and cause side effects.

Let’s see an example. Suppose that we add a getNoOfDrivers() method in to our Car class in Java and we also make it mutable in both Kotlin and Java by allowing an external caller to modify the number of drivers variable like this:

Java

public class Car {

private int noOfDrivers;



public Car(final int noOfDrivers) {

this.noOfDrivers = noOfDrivers;

}



public int getNoOfDrivers() {

return noOfDrivers;

}



public void setNoOfDrivers(final int noOfDrivers) {

this.noOfDrivers = noOfDrivers;

}

}

Kotlin

class Car(var noOfDrivers: Int)

Suppose we share an instance of this Car class across 2 threads: Thread_1 and Thread_2. Thread_1 wants to do some calculation based on the number of drivers so it calls getNoOfDrivers() in Java or accesses the noOfDrivers property in Kotlin. Meanwhile Thread_2 comes in and modifies the noOfDrivers variable. Thread_1 does not know about this change and happily carries on with it’s calculations. These calculations would be wrong since the state of the world has been modified without by Thread_2 without Thread_1 knowing about them.

The following sequence diagram illustrates the issue: