Why are some Java functions able to change an immutable Kotlin object?
functions that doesn't compile has nothing to do with kotlin but how covariant and contravariant collections are handled by java.
from Java Generics and Collections
You cannot put anything into a type declared with an extends wildcard—except for the value null, which belongs to every reference type
for example if you have following code.
List<? extends Number> numbers = new ArrayList<Integer>();
Then you can do this
numbers.add(null);
but if you tried to do any of the following
numbers.set(0, Integer.valueOf(10)); // case 1
numbers.set(1, numbers.get(0)); // case 2
in case 1 compiler will not let you do it because there is no way for the compiler to know the exact type of list, in this case its a list of integers in some other case it may be assigned a list of doubles based on some runtime condition.
in case 2 the compiler is not able to confirm the type of object that is being inserted into the list, and an error is produced. you can solve the problem in case 2 using Wildcard Capture.
Second is your question about mutating kotlin lists in java methods.
we have to understand that kotlin collections classes are same old java collection classes and kotlin doesn't have its own collections implementation. what kotlin does is that it divides the java collection interfaces into mutable and read only. if you create an array list in kotlin and then check its class you will get same java.util.ArrayList
Now given that java doesn't have any notion of mutable list and read only list as kotlin does, there is no way to stop java methods from mutating your read only kotlin list. because for java code that is just a list implementation.
following is the relevant text from book Kotlin in Action
When you need to call a Java method and pass a collection as an argument, you can do so directly without any extra steps. For example, if you have a Java method that takes a java.util.Collection as a parameter, you can pass any Collection or Mutable Collection value as an argument to that parameter.
This has important consequences with regard to mutability of collections. Because Java doesn’t distinguish between read-only and mutable collections, Java code can modify the collection even if it’s declared as a read-only Collection on the Kotlin side. The Kotlin compiler can’t fully analyze what’s being done to the collection in the Java code, and therefore there’s no way for Kotlin to reject a call passing a read-only Collection to Java code that modifies it.