Search code examples
kotlin

Behavior of mutable list differs in kotlinc and REPL ki


I ran the following code in both kotlinc and ki (github)

data class Person(val name: String, val roles: List<String>)

val m = Person("bob", mutableListOf("developer"))
m.roles.addFirst("a")

In kotlinc, I got an error message:

 > kotlinc -script Immutable.kts 
Immutable.kts:4:9: error: unresolved reference 'addFirst'.
m.roles.addFirst("a")
        ^

However, ki allowed me to modify the mutable list roles:

> ki
ki-shell 0.5.2/1.7.0
type :h for help
[0] data class Person(val name: String, val roles: List<String>)
[1] val m = Person("bob", mutableListOf("developer"))
[2] m.roles.addFirst("a")
[3] m.roles
res3: List<String> = [a, developer]

So, why the code returns two different outcomes depending on how it was executed?

I got confused by the use of listOf() and mutableListOf(). I understand that listOf() creates an immutable list (addFirst() is not available, so we cannot change the list), whereas mutableListOf() returns a mutable list (addFirst() is available, so we can change the list). However, that behavior does not apply when using data classes in kotlinc, is that correct? Such a difference is expected when using ki?

I am using these versions:

$ kotlinc -version
info: kotlinc-jvm 2.0.0 (JRE 22+36-2370)

$ javac -version
javac 22

$ ki --version
ki-shell 0.5.2/1.7.0

Solution

  • The compiler respects strictly the publicly declared types. The roles attribute is of type List, so not mutable. Therefore, you cannot add elements to it, because there is no guarantee that the underlying list instance is mutable.

    I think Ki might work more as a debugger, and automatically check the runtime type to infer what are available methods.

    To sum up: in term of Kotlin syntax, the compiler is strict and right, and Ki is more permissive because, as a debugger, it performs additional checks underneath to ease on the fly evaluations.