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
I got this answer from StackOverflow:
This isn’t about data classes as such — just about declared types. In both versions of your code, you’re creating a
MutableList
, but storing it in aList
property.MutableList
is a subtype ofList
, so it’s OK to store it there — that’s an upcast. From then on, the compiled code knows only that it’s aList
. (After all, you could easily write some other code which stored an immutable list in that property.) However, Ki can do something that a compiler can’t: it can check the actual type at runtime.And here, it seems to see that although the reference is of a
List
type, at this point in the run the object it’s actually referring to is aMutableList
, and so it’s OK to treat it as mutable. — Now, whether a REPL should be doing this is another question… (I don’t know Ki; it’s possible that this is unintended behaviour!)
Is that answer correct? If so, is it OK for kotlinc
and ki
to treat mutable lists differently?