DEV Community

Cover image for Mutable vs Immutable in Kotlin: Why Immutability Matters
Phat Voong
Phat Voong

Posted on

Mutable vs Immutable in Kotlin: Why Immutability Matters

Understanding the difference between mutable and immutable can significantly impact your code's reliability, readability, and maintainability. Here's a deep dive into these concepts, with examples to illustrate why immutability is often the preferred choice.

Mutable vs Immutable: The Basics:

  • Mutable: Refers to anything whose state or data can be changed after it is created. This can apply to variables, collections, and objects.
  • Immutable: Refers to anything whose state or data cannot be changed once it is created. This immutability applies to variables, collections, and objects.

Example:

// mutable
var mutableList = mutableListOf("A", "B", "C")
mutableList.add("D")
println(immutableList) // Output: [A, B, C, D]
Enter fullscreen mode Exit fullscreen mode

There are two mutable aspects here. First, the var keyword allows the list to be reassigned to another value. Second, mutableListOf allows the list to be modified after initialization.

// immutable
val immutableList = listOf("A", "B", "C")
// immutableList.add("D") // This will not compile
println(immutableList) // Output: [A, B, C]
Enter fullscreen mode Exit fullscreen mode

Why Mutable is Bad?

1- Thread Safety Issues:
Mutable objects can lead to concurrent modification problems in a multi-threaded environment. This can cause unpredictable behavior and hard-to-find bugs.

var sharedList = mutableListOf<Int>()

// Thread 1
Thread {
    for (i in 1..1000) {
        sharedList.add(i)
    }
}.start()

// Thread 2
Thread {
    for (i in 1..1000) {
        sharedList.add(i * 10)
    }
}.start()

// Result may vary and can lead to data corruption
Enter fullscreen mode Exit fullscreen mode

2- Unexpected Side Effects - Unpredictable Code:
Mutable objects can be changed from different parts of a program, leading to unexpected side effects and bugs that are difficult to trace.

fun modifyList(list: MutableList<String>) {
    list.add("D")
}

val list = mutableListOf("A", "B", "C")
modifyList(list)
println(list) // Output: [A, B, C, D]
Enter fullscreen mode Exit fullscreen mode

Since the list is mutable, its values can change unpredictably. To understand all the modifications made to the list, you must trace the code from its initialization to every point where it is used.

3- Ease of Testing:
Immutable objects simplify testing because their state cannot change. This eliminates side effects and makes it easier to write reliable unit tests.

fun addElementToList(list: List<String>, element: String): List<String> {
    return list + element
}

val originalList = listOf("A", "B", "C")
val newList = addElementToList(originalList, "D")

assert(originalList == listOf("A", "B", "C"))
assert(newList == listOf("A", "B", "C", "D"))
Enter fullscreen mode Exit fullscreen mode

Conclusion
In Kotlin, prefer using val over var and immutable collections like List instead of MutableList whenever possible. This simple practice can lead to significant improvements in your code quality.

While mutable objects have their place, especially in scenarios requiring frequent updates, immutability often leads to safer, more maintainable, and predictable code.

What's ahead: Understanding immutability sets the stage for the next things - Declarative code and Functional programming.

Top comments (1)

Collapse
 
tina_nguyen profile image
Tina Nguyen

Nice post!