Blog Infos
Author
Published
Topics
, , , ,
Published

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:

val myList = mutableListOf("Item1", "Item2")
myList.add("Item3") // Modifying the list, but the reference remains the same
view raw my_list.kt hosted with ❤ by GitHub

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

class Sample {
private val text: String = "title"
}
view raw sample_class.kt hosted with ❤ by GitHub

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

private final Ljava/lang/String; text
@Lorg/jetbrains/annotations/NotNull;() // invisible

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Kobweb:Creating websites in Kotlin leveraging Compose HTML

Kobweb is a Kotlin web framework that aims to make web development enjoyable by building on top of Compose HTML and drawing inspiration from Jetpack Compose.
Watch Video

Kobweb:Creating websites in Kotlin leveraging Compose HTML

David Herman
Ex-Googler, author of Kobweb

Kobweb:Creating websites in Kotlin leveraging Compose HTML

David Herman
Ex-Googler, author o ...

Kobweb:Creating websites in Kotlin leveraging Compose HTML

David Herman
Ex-Googler, author of Kob ...

Jobs

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:

interface State<out T> {
val value: T
}
interface MutableState<T> : State<T> {
override var value: T
operator fun component1(): T
operator fun component2(): (T) -> Unit
}
val state: State<String> = remember { mutableStateOf("text") }
(state as MutableState<String>).value = "changed"
view raw state.kt hosted with ❤ by GitHub

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:

data class Sample(
val name: String,
val url: String,
val age: Int
)
view raw sample.kt hosted with ❤ by GitHub

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.

public final class com/skydoves/server/driven/core/model/Sample {
// access flags 0x12
private final Ljava/lang/String; name
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x12
private final Ljava/lang/String; url
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x12
private final I age
}
view raw sample.java hosted with ❤ by GitHub
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.

If you have any questions or feedback on this article, you can find the author on Twitter @github_skydoves or GitHub. If you’d like to stay updated with the latest information through articles and references, tips with code samples that demonstrate best practices, and news about the overall Android/Kotlin ecosystem, check out ‘Learn Kotlin and Android With Dove Letter’.

As always, happy coding!

— Jaewoong

This article is previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE
Menu