Effective Kotlin: Item 17 — Minimize mutability

When talking about mutability Joshua Bloch in Effective Java states, “Classes should be immutable unless there’s a very good reason to make them mutable”. An immutable class is one whose external state cannot change once created. Immutable classes lend themselves to a functional approach where methods return the result of applying a function to the operand without modifying it.

Joshua provides five rules for class immutability:

  1. Don’t provide methods that modify the object’s state
  2. Ensure that the class can’t be extended
  3. Make all fields final
  4. Make all fields private
  5. Ensure exclusive access to any mutable components

One of the most common use cases in Java is immutable value classes. Kotlin’s data classes negate the need to use tools like AutoValue to help generate these. Kotlin also helps by ensuring classes are final by default, but we need to be aware of a few more points.

When first learning Kotlin it is easy to believe that the val keyword means immutable and var mutable, however, val, as noted in the documentation means read-only, i.e. val does not guarantee object immutability. val and var only control the reference and not the object instance assigned.

For example, a data class containing an IntArray can have its data modified as IntArray is mutable:

data class NotImmutable(val array: IntArray)

NotImmutable(intArrayOf(1, 2)).array[0] = 3

Kotlin also allows custom getters meaning val doesn’t even guarantee immutable references:

val mutableReference: Int
get() = Random().nextInt()

Of course, if you follow Kotlin’s coding conventions, then this should be declared as a function and not as a property.

As an interesting side note, you can override a val as a var in a subclass, but not the other way around. I’m yet to find a real-world example of when this would be useful, but the best case I’ve seen is from Mark Allison creating a mutable/immutable sealed class.

As pointed out in Effective Java immutable classes can come at a cost to performance with the suggestion being to generate these with a static factory method, as shown in Item 1 — Consider static factory methods instead of constructors using companion objects, to make it trivial to add caching in the future should the need arise.

companion object {
fun create(property: Int) = Immutable(property)

As with Java, when creating immutable classes in Kotlin, we still have to pay attention to the objects our val keywords reference to ensure these are immutable.

Each week I am looking at “items” from Joshua Bloch’s well-respected book, Effective Java to see how it applies to Kotlin. You can find the rest of the items I’ve covered at Effective Kotlin. Please let me know your thoughts.

Matt Dolan has been eating doughnuts and developing with Android since the dark days of v1.6.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store