Lists: read-only vs mutable
A List is an ordered collection that allows duplicates and is indexed from 0. Kotlin splits every collection type into two interfaces: List<T> has only reading operations (size, get, contains, indexOf), and MutableList<T> adds add, remove, set and clear. listOf() gives you the first, mutableListOf() the second.
fun main() {
val langs = listOf("Kotlin", "Java", "Go")
println(langs[0])
println(langs.size)
println("Go" in langs)
println(langs.indexOf("Java"))
val cart = mutableListOf("milk")
cart.add("eggs")
cart += "bread" // same as add
cart[0] = "oat milk" // same as set(0, ...)
cart.removeAt(1)
println(cart)
println(cart.first() + " / " + cart.last())
}Kotlin
3
true
1
[oat milk, bread]
oat milk / breadCall cart.add(1, "butter") before printing and predict where it lands.
val cart = mutableListOf(...) means the variable cart always points at the same list. The list itself can still grow and shrink. Read-only-ness comes from the type (List vs MutableList), not from val.When a function needs to build a list step by step but should hand back a read-only one, use buildList { }. Inside the block you have a MutableList; what comes out is a List. buildSet and buildMap work the same way.
fun evensUpTo(n: Int): List<Int> = buildList {
for (i in 0..n) {
if (i % 2 == 0) add(i)
}
add(-1) // a sentinel at the end
}
fun main() {
val evens = evensUpTo(8)
println(evens)
println(List(4) { it * it }) // List(size) { index -> value }
println(emptyList<String>().isEmpty())
}[0, 2, 4, 6, 8, -1]
[0, 1, 4, 9]
trueCalling add on a read-only List
fun main() {
val names = listOf("Ada", "Linus")
names.add("Grace")
println(names)
}Main.kt:3:11: error: unresolved reference 'add' on receiver of type 'List<String>'.
names.add("Grace")
^^^listOf returns the read-only List interface, which simply has no add function. The compiler is not saying the list is frozen at runtime; it is saying the type you hold does not offer mutation.
If the list really needs to change, create it with mutableListOf. If you only need a new list with one more item, use names + "Grace", which returns a fresh list and leaves the original alone.
fun main() {
val names = mutableListOf("Ada", "Linus")
names.add("Grace")
println(names)
}