In Kotlin, what is the difference between List and MutableList, and where does that distinction actually exist at runtime?
answer
- Read-only != immutable
- Distinction is compile-time only
- MutableList extends List + adds add/remove/set
- Same object can be aliased as both
- No separate immutable runtime class
basics
~20 sList has no add or remove methods, MutableList does. But it's only a rule the compiler checks. At runtime both are usually the same Java ArrayList, so the read-only promise can be broken from Java code.
solid answer
~30 sKotlin splits the collection hierarchy into a read-only view (kotlin.collections.List) and a mutable one (kotlin.collections.MutableList, which extends List and adds add/remove/set). This distinction is purely compile-time: the Kotlin compiler refuses to call mutating methods on a List reference. At runtime there is no separate immutable class — a List is typically just a java.util.ArrayList. So 'read-only' means 'this reference cannot mutate it', not 'this collection can never change'. The same underlying object can be referenced as MutableList elsewhere, or handed to Java, where the read-only contract does not exist at all. Read-only is not the same as immutable.
code
kotlin · 5 linesval mutable = mutableListOf("a", "b")
val view: List<String> = mutable // read-only reference to SAME object
// view.add("c") // does not compile
mutable.add("c") // allowed via the mutable alias
println(view) // [a, b, c]go deeper
Knows List lacks add/remove while MutableList has them, and that listOf is read-only.
Articulates that the distinction is compile-time only and that aliasing lets the same object be mutated through another reference.
Distinguishes read-only from immutable, knows .toList() defensive copies, and reaches for kotlinx.immutable when true immutability is required.
Frames API design tradeoffs: exposing read-only views vs defensive copies vs persistent collections, and the performance/safety implications across module boundaries.
## The two interfaces Kotlin defines its own collection interfaces in the `kotlin.collections` package: - **`List<T>`** — a *read-only* view. It exposes `size`, `get`, `contains`, `iterator`, etc., but **no** `add`, `remove`, `set`, or `clear`. - **`MutableList<T>`** — extends `List<T>` and *adds* the mutating operations (`add`, `remove`, `set`, `clear`). The same pattern exists for `Set`/`MutableSet`, `Map`/`MutableMap`, `Collection`/`MutableCollection`, and `Iterator`/`MutableIterator`. ## "Read-only" is compile-time only This split is enforced **only by the compiler**. There is **no separate immutable runtime class**. When you write `listOf(1, 2, 3)`, you get a `java.util.Arrays$ArrayList`-style object; `mutableListOf(...)` gives you a `java.util.ArrayList`. Both implement `java.util.List`. The word *read-only* describes what the **reference type** lets you do, not a guarantee about the object. - `List` = "through *this* reference you may not mutate." - `Immutable` = "this object can *never* change." Kotlin's stdlib `List` is **not** this. ## Why this matters Because it is compile-time only, the guarantee can be bypassed: ```kotlin val mutable = mutableListOf(1, 2, 3) val readOnly: List<Int> = mutable // upcast — same object mutable.add(4) println(readOnly) // [1, 2, 3, 4] — it changed! ``` The `readOnly` reference cannot call `add`, but the underlying object is shared and was mutated through the other reference. This is *aliasing*, not a compiler bug. ## Key keywords/APIs - `listOf` / `mutableListOf` / `setOf` / `mapOf` - `kotlin.collections.List` vs `kotlin.collections.MutableList` - `.toList()` makes a *defensive copy* (a new read-only snapshot) If you truly need an unchangeable collection, copy defensively (`.toList()`) or use a genuinely immutable type (e.g. the `kotlinx.collections.immutable` library's `PersistentList`).
- How do you make a genuine read-only snapshot that won't change when the source mutates?Call `.toList()` (or `.toSet()`/`.toMap()`) to create a defensive copy — a new collection that does not share storage with the original.
- Does Kotlin have a truly immutable List in the standard library?No. The stdlib only offers read-only *interfaces*. For real immutability use kotlinx.collections.immutable (PersistentList/ImmutableList) or copy defensively.
A List reference is like a museum window: you can look but not touch — yet someone with the door key (a MutableList alias) can still rearrange the exhibit.
saying these in an interview costs you the question
- Claiming List is immutable and can never change
- Saying listOf returns a special immutable class
- Thinking upcasting to List copies the data
- Believing the compiler prevents all mutation of the underlying object