The val Property != Immutable in Kotlin

The val Property != Immutable in Kotlin

When declaring properties, it’s crucial to determine whether a property should be mutable, as this decision can directly impact your software’s behavior. This is a fundamental consideration, as it can lead to potential issues in your code if not handled carefully.

When using a state management library like Jetpack Compose Runtime, the immutability of properties becomes crucial. It directly impacts whether or not a composable function can be determined as skippable, affecting your application’s performance.

This article explores the intriguing question of whether a property defined with the val keyword in Kotlin is truly immutable or simply read-only — an interesting topic recently raised in Dove Letter. Dove Letter is a subscription repository where you can learn, discuss, and share new insights about Android and Kotlin. If you’re interested in joining, be sure to check out “Learn Kotlin and Android With Dove Letter.”

Importance of Immutability

There are several critical advantages of declaring properties as immutable whenever possible in the programming world:

  • Predictability and Safety: Immutable properties can’t be changed after initialization, making it easier to understand and predict their behavior, reducing the risk of unintended side effects.
  • Avoiding Side Effects: Mutable properties can lead to unpredictable behavior. Immutability keeps the state stable, reducing the chance of bugs.
  • Functional Programming: Many modern paradigms, like functional programming, emphasize immutability, leading to more modular, reusable, and maintainable code that’s easier to scale.
  • Simplified State Management: Immutability simplifies state management, especially in like Jetpack Compose, where stable and immutable objects improve performance by reducing unnecessary recompositions.
  • Thread Safety: Immutable properties are inherently thread-safe, preventing concurrency issues like race conditions without needing complex synchronization.

You’ve understood the importance of immutability and how it impacts various aspects of software quality. Now, let’s dive deeper into how immutability applies to properties in Kotlin.

Immutable vs. Read-Only

In Kotlin, you can declare properties as mutable using the var keyword or as non-reassignable using the val keyword, preventing changes to their value. But does declaring a property with val truly makes it immutable?

Curious about this topic, I created a poll to see how the Android community typically approaches the immutability of Kotlin properties. Here are the results:

As you can see from the poll, out of 247 participants, 59% consider the val property to be read-only, while 41% believe it is truly immutable.

If you read Kotlin’s official documentation on properties, you’ll find that there are two ways to declare properties: var and val, as described below:

Properties in Kotlin classes can be declared either as mutable, using the var keyword, or as read-only, using the val keyword.

Surprisingly, the official documentation doesn’t mention “immutable” or “immutability” anywhere. It exclusively refers to val properties as “read-only.” The reasoning is simple: two clear distinctions explain why a val property is considered read-only but not truly immutable in most cases.

  1. Objects can still be modified

Even when a property is declared with the val keyword, the object it refers to can still be changed. For example, consider the following property:

https://medium.com/media/e162d7388d596f21b47bd87597c61807

Although the reference myList cannot be reassigned, the list items can still be modified. Let’s see another example.

https://medium.com/media/0b733835eeac5f65631ca5071be40d74

If you decompile the Sample class and examine the Kotlin bytecode, you’ll see how it is ultimately transformed in the JVM environment.

https://medium.com/media/74cff14201e50c3ffece98ea86a78246

val properties in Kotlin are compiled to final in the bytecode, which, according to the Java Language Specification, means the following:

Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.

Eventually, the val keyword only ensures the reference is constant but does not guarantee the object’s immutability.

2. Classes and interfaces can still override properties

The other reason is that a class or interface can still override the property, meaning there’s a possibility for the value of a val property to change. This makes val not strictly immutable in all cases. For example, consider the State interface in Jetpack Compose:

https://medium.com/media/3960ef266f582a580ebc9f20d246f0f8

Even though value is declared as val, subclasses can override this property, potentially changing its behavior or value. This flexibility shows that val ensures read-only access to the reference but doesn’t fully guarantee immutability, especially when inheritance or overriding is involved.

This clarifies the distinction: it’s clearer to describe the val property as reference immutability (the reference cannot change) & object mutability (the object itself can be modified) rather than simply calling it “read-only.”

Immutable Object

So, when you define an object, is it truly immutable? For a class to be genuinely immutable, it must consist entirely of read-only properties, and those properties must be either primitive types or objects that do not allow any changes to their internal states, but it should also prevent overriding by using declaring as a data class. Consider the following data class example:

https://medium.com/media/2d8361f04bfee356d134153abb5ad1fe

Data classes in Kotlin don’t allow inheritance, so if they consist entirely of immutable properties, you can consider them truly immutable objects. When decompiled into bytecode, you’ll see that they are defined as final classes with final field properties, ensuring they cannot be modified or extended.

https://medium.com/media/83166124e90f0c388edebce90d68bf70

Conclusion

In this article, you’ve explored the importance of immutability in software and examined whether properties defined with val in Kotlin are truly immutable. While immutability can be interpreted in various ways depending on context and perspective, understanding the fundamental concepts of immutability in your primary programming language is crucial for reducing bugs and improving maintainability.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

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