3

I try to have a deep understanding of collection in Kotlin. I failed keep mutability of List when doing that:

  val intsA = arrayListOf(1, 2, 3)
  val intsB: List<Int> = intsA
  intsA.add(4)
  println("intsA = $intsA && intsB = $intsB")

resulting:

intsA = [1, 2, 3, 4] && intsB = [1, 2, 3, 4]

Yes I know I am passing the reference and I could do it more safely by doing:

val intsB: List<Int> = intsA.toList()

still I do not really understand what is happening behind the scene? Why the default casting in Kotlin is not to done more safely? Because it can be a bit dangerous to have that piece of code somewhere in code and later on use it thinking that it is immutable like here:

fun main(args: Array<String>) {

    val intsA = arrayListOf(1)
    val intsB: List<Int> = intsA
    val myClass = MyClass(intsB)

    intsA.add(2)
    println("intsA = $intsA && intsB = $intsB && myClass = $myClass")

}

class MyClass(val list: List<Int>){
    override fun toString(): String {
        return "MyClass(list=$list)"
    }
}

resulting:

intsA = [1, 2] && intsB = [1, 2] && myClass = MyClass(list=[1, 2])
JPIyo
  • 75
  • 1
  • 5
  • You're complaining about Kotlin, but you're making a basic error that any reference on OOP would caution you not to do. The same issue can arise in Java if you create an array list and then pass that list into the Collections.unmodifiableList() method. There is no language in the world that can protect the programmer from himself. – AutonomousApps Jul 23 '18 at 03:30
  • By the way I like kotlin... It is not complaining. I try to understand! – JPIyo Jul 25 '18 at 07:07

2 Answers2

5

The .toList() call isn't some fancier cast that enables this "immutabilty". That function simply constructs an entirely new List internally, and copies the elements from the original list into the new one. That's why modifications to the original no longer affect the new list.


As for why it's possible to have a reference to the same list both as a List and a MutableList - this really is a basic feature of OOP. You can expose the same object through various interfaces for your different clients, with different operations available on them.

zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • Thanks @zsm13 for your answer. I have already understood the first argument... It is obvious! But the second is maybe "basic" OOP but not trivial for me, sorry :-). Still, end to end, I feel that wrong to not be able to garantie a functional coherence of my objects though code. EndToEnd there is no way I could accept that an object that I declare has immutable can mutate somewhere else in the code. But I still want to understand why... to avoid that issue in my code. – JPIyo Jul 25 '18 at 11:04
  • For me, the issue is possiblity to assignments ArrayList - List (that why I spoke about casting). The object is therefore exposed to 2 interface that have opposite functionnal purposes. I know you will say that OOP allow it. But it doesnt means that is acceptable. Maybe there is issue in the design itself? (Here again it not complaining about Kotlin... I want to undersand) – JPIyo Jul 25 '18 at 11:08
  • 1
    I think what's bothering you is that `List` and `val` are often talked about as being "immutable" in Kotlin. They are not, they're simply read-only, which is vastly different. These both provide read-only views, but of potentially very mutable objects. If you need actual immutability, you can look for library solutions, whether they're [for Java](https://stackoverflow.com/questions/7713274/java-immutable-collections) or [for Kotlin](https://github.com/Kotlin/kotlinx.collections.immutable). – zsmb13 Jul 25 '18 at 12:01
0

A val doesn't mean a list is immutable. It just means the reference can't be changed. There is no immutability in the code you have provided. What you probably wanted to do was use listOf (which creates an immutable List) instead of arrayListOf, which creates an instance of ArrayList, which is mutable.

Btw, Kotlin itself doesn't provide support for immutable collections yet, but this might be implemented one day.

Erik Pragt
  • 13,513
  • 11
  • 58
  • 64
  • Thanks for you answer Erik, the discussion not 'val'. It is about the possibility to have a List which can mutable by a mistake in the code like ```val intsA = arrayListOf(1). ---> val intsB: List = intsA``` – JPIyo Jul 25 '18 at 11:15
  • Hi JPlyo, I understand, which is why I mentioned the use of listOf vs arrayList. I don't understand why you are concerned about mutating a mutable list when you have an immutable option available. – Erik Pragt Jul 25 '18 at 16:16
  • It is just learning test about collections behaviors :-). I do not really the intention to using in really life app! – JPIyo Jul 25 '18 at 21:57