What is meant by "immutable data"?


#1

@abreslav presented some possible future features (see slide 26), one of them beeing “immutable data”. Since it is already possible to create immutable data structures in Kotlin I wonder what is meant by this term.

What is it?


#2

Copying the description which was used in the survey:

Kotlin has immutable variables (val’s), but no language mechanisms that would guarantee true “deep” immutability of the state. If a val references a mutable object, it’s contents can be modified:

val myVal = arrayListOf(1)
myVal.add(2) // mutation

Read-only interfaces for collections help somewhat, but we’d need something like readonly/immutable modifier for all types to ensure true immutability. Syntax is purely provisional:

class Foo(var v: Int)

immutable class Bar(val foo: Foo) // error: mutable reference from immutable class

#3

Wow! When will this feature come?


#4

This feature seems to be very hard to implement without some dramatic changes to language. Maybe it is better to use annotations and lint inspections instead?


#5

If an annotation + inspections could accomplish this, the compiler could do it as well.


#6

Compiler probably can do that, but I am not sure if those restrictions would be natural or they will overburden the language. In my opinion kotlin have too many reserved words and additional language constructions as is.
To top it all, hard restrictions could make this feature unusable. If it is implemented as said in @yole post, than you can’t use reference to any class with mutable fields. Almost all classes have such fields and you will be limited only to your own immutable classes. Kotlin already have data classes for that.


#7

immutablee as keyword may become really interesting if the compiler changes is behaviour, e.g. sealed class in when, data class or const val.

immutable data class can be elected for stack allocation, copy by value or parallel computation.


#8

You can find an answer to your question in the blog post.


#9

That’s not the case. For an inspection, it’s acceptable to detect only some of the potentially problematic places, and to report occasional false positives (this is undesirable, but in many cases a worthwhile tradeoff). A compiler analysis has to be precise.


#10

Hello guys, I’m new here. I was taking a look at this conversation and now I’m interested. So, I have a doubt.
@yole has mentioned:

val myVal = arrayListOf(1)
myVal.add(2) // mutation

How can I add elements in an array without lose the immutability? I tried the following example:

fun addElement(args : ArrayList<String>, arg : String) : List<String> {
    val newArray = ArrayList<String>(args)
    newArray.add(arg)
    return Collections.unmodifiableList(newArray)
}

Thank you very much for the help.


#11

val does not mean immutable, it means that variable is not variable, or on other words it could not be reassigned to new value. But since the value itself is reference, its content could be changed without modifying the reference.

True immutability means that object could not be mutated in any way and always remains the same. For now JVM does not implement this on the language level, so the only way to ensure some object is immutable is to check that all objects which are referenced inside are immutable themselves, which is not so simple and seldom could not be checked in compile time.

I understand, that Kotlin team is working on solutions for that, but it is not that simple.


#12

Oh, got it. @darksnake

But in this context:

fun addElement(args : ArrayList<String>, arg : String) : List<String> {
    val newArray = ArrayList<String>(args)
    newArray.add(arg)
    return Collections.unmodifiableList(newArray)
}

Note that I’m adding the new element in the array that I created by the passed one.
This “add”, it is not immutable, but in this context that I have the control in the return of the function I’m making sure the List is immutable.
So in the external context, outside of this method, another programmer won’t be able to modify this list.

Am I right?


#13

I might be wrong, but I thought true immutability is impossible on the JVM. I mean I could always use reflection to access the backing fields of any property. Also this would basically prohibit java interop as there is no guarantee what the java side of the code is doing.
That being said immutable data structures like the one in https://github.com/Kotlin/kotlinx.collections.immutable have their advantages.
I’m just not sure something like the immutable keyword discussed above would work well in Kotlin.


Yes. Depends on the return value of Collections.unmodifiableList. As long as the data structure returned is properly implemented there should be no way of modifying your returned list.


#14

It is not possible to enforce in runtime at least until Valhalla, but it is possible to check it in compile time. For example, introduce a bytecode flag and force compiler to check that all of members have this bytecode flag. Of course, it would require to either not use Java objects, or create some kind of automatic markings the same way kotlin treats Java nullability (I can state that it would never be null, but it still could throw NullPointerException). I do not say, it should be done this way, but it is possible in theory.


#15

But @Wasabi375, the example that I sent with the unmodifiable list, is it a good way to say that I’m adding an element?
Because the immutable concept says we should return a new list with the added value and we must not add the element inside a list itself.
What do you guys think?


#16

The add here is limited to the context that I’m working, the immutable is happening when I’m returning the unmodifiable list.


#17

Basically the idea is that the permanent lists you work with are never changed.

val list = listOf(1, 2, 3, 4)

the content of this list is never changed, it will always contain 1, 2, 3 and 4. If you need to edit the list you don’t change the list itself, but you create a new list. So yes your example is a valid implementation of the immutable concept. The fact that you use a temp list inside of the function does not matter as never gets used again and there is no way to access this temp list. Also in an optimal case you would only use immutable implementations of the List interface. That way you can guarantee that no one ever changes the list by accident.


#18

You can do a lot of things.In this case you ensure that result of the function could not be modified later, but you cannot guarantee that on the language level. The List itself lacks mutation methods in kotlin, but someone could try to call it from java and try to change something (and get an exception). Also, you now, that the object could not be changed, but compiler does not, so it could not apply some optimizations which would do good to the program.


#19

But, for regular/common developers, do they need to be worried with the immutability in the byte code/compiler level? Or they just should be worried only with the state changing?


#20

Depends. Most times I would say you don’t need to care to much about optimizations. That being said if you create copies of immutable data structures often (to change them) this can get quite slow in case of big data structures if no optimization is done. I don’t think the unmodifiableList from java has no optimizations in that regard.
The kotlinx.collections.immutable module has some immutable list, set and map implementations, I don’t know how optimized they are. As far as I know they are based on pcollections.