Kotlin: Mutability

Kotlin is a very rich language with much subtlety tucked away. In this occasional series (meaning that there will be occasional, standalone posts covering distinct areas) we’ll explore some of these subtleties. In this post we’ll take a look at mutability.

Mutability is a core concept in Kotlin, but all is perhaps not what it seems. The fundamental concept here is if we declare variables using var then they are mutable and can be reassigned with another value, whereas if we declare variables using val then they are immutable and cannot be reassigned. However, it is important to remember that var and val only control the variable itself, and not the object instance that is assigned. We can illustrate this with a simple example:

We can happily change mutable as much as we like, but we cannot reassign immutable with a different value. This may give the impression that we cannot change immutable, but that is actually not the case. While the variable itself is immutable, the instance of MyClass that it references is mutable:

At first this feels a little counter intuitive, but it makes perfect sense when we consider what is actually going on. While the variable named immutable cannot be changed it references a data class which has a single field named value which can be changed because it is declared as a var.

If we want to make the variable named immutable truly behave as an immutable object then we would need to change the implementation of MyClass itself to be immutable by making its property named value immutable by declaring it as a val:

On the face of it this would appear to now break the mutability of the variable named mutable but this is not the case. While we can no longer directly alter the value property of the MyClass instance that it references, we can assign it with a new instance of MyClass which as a different value property:

Of course there is the overhead of having to create a new object each time, but it does give us a much cleaner and safer mutability contract. It is for this reason that we should strive for immutability wherever possible because it is easier to relax an immutable object to a mutable one (through new instance creation) than it is to tighten a mutable object to be an immutable one.

We can leverage Kotlin sealed classes to allow us to create mutable and immutable variants of the same underlying class:

It is not possible to directly create an instance of MyValue, instead we create an instance of either MyValue.Immutable or MyValue.Mutable. The underlying value property in MyValue is a var, but we override this in MyValue.Mutable to make it a var. Kotlin allows us to override a val property in the base class as a var, but not the other way around.

We can also include some convenience methods which allow us to convert between mutable an immutable variants of the same base class.

Using this quite simple pattern we get concrete enforcement of our mutability contracts at compile-time:

It is also worth mentioning that there’s a really nice trick that we can use to make a var property immutable:

Even though the property named value is declared as a var, we can make its setter private and it will behave as though it was declared are a val:

Kotlin provides us with some nice, clean mechanisms for controlling the mutability of objects, but we also need to think carefully about how we structure or classes to provide consistency.

As the concepts covered here are largely self-contained, and the code snippets can be copied / pasted directly there is no accompanying source code repo for this article.

© 2018, Mark Allison. All rights reserved.

CC BY-NC-SA 4.0 Kotlin: Mutability by Styling Android is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Permissions beyond the scope of this license may be available at http://blog.stylingandroid.com/license-information.

Leave a Reply

Your email address will not be published. Required fields are marked *