Kotlin: val does not mean immutable, it just means readonly, yeah
Artem ZinnatullinHey hey, dear reader!
I'm seeing how people (including myself some time ago) tend to think that val
in Kotlin means immutable. Unfortunately, this is not true 😞
Obviously, val
can not guarantee that underlying object is immutable, that's clear.
But can we say that
val
guarantees that underlying reference to the object is immutable?
No...
Kotlin allows you declare get()
of the val
which breaks immutability of the property and leaves only read
permission for external "users".
Example:
class OhNo {
val yeah: Int
get() = Random().nextInt()
}
Things are especially sad when you declare val
in an interface
:
interface SomeService {
val user: User
}
Until you check implementation (which is not always possible) you can't be sure that value will be same each time you read it from the property.
Real world example is List.size
from Kotlin stdlib.
How to live with that?
We have a convention (hopefully haha, at least I point to that in code reviews) internally in our team (100% Kotlin) to not declare properties like val currentSomething: Something
, if value can be different each time you read it — please declare a function: fun currentSomething()
or just fun something()
because when it's a function then it's clear that resulting value can be different on each call. But for types that clearly represent "volatility" themselves, like rx.Observable
it's ok to have them as val
.
Good thing is that in data class
you can't define get()
for properties declared in the constructor, but you can do it for non-constructor properties.
We've discussed that with @abreslav and @volebamor from Kotlin team, but looks like there is nothing Kotlin team can do about this at the moment. Would be great to have clear separation of immutable
val
andreadonly val
, but that's just dreams. Though I've opened an issue for highlighting thatval
has overridenget()
in IDE.
Stay immutable!