I just started to explore the language Kotlin. I\'m struggling with inheritance, var&val and side-effects.
If I declare a trait A
with a val x
I would consider this a feature, as changing val to var imposes weaker usage restrictions and can't break any superclass code. Similar situation can be observed with visibility modifiers:
trait A {
protected fun print() {
...
}
}
class AImpl: A {
public override fun print() {
...
}
}
In this example visibility restrictions are also relaxed by a subclass, although some people are considering this technique as an antipattern.
How do I protect values from being changed by inheritance?
In kotlin you can explicitly define if any particular class member can be overriden by a subclass using open
modifier. In traits, however, all the members are open by default. The solution is to replace trait with class, so you'll be able to control inheritance:
abstract class A {
fun print() {
...
}
val x : Int = 2;
}
class AImpl(x : Int) : A() {
override var x = x // compilation error
}
You can make your val
final
, i.e. forbid overriding it at all.
If you define a val
in a class, it is final
by default.
Also, if you need to override a val
with a var
, but do not want the setter to be public, you can say so:
override var x = 1
private set
Overriding a val
with a var
is a feature. It is equivalent to adding a set-method while in the superclass there was only a get-method. And this is rather important in implementing some patterns, such as read-only interfaces.
There's no way to "protect" your val
from being overridden in a way that allows changing mutation other than making it final
, because val
does not mean "immutable reference", but merely "read-only property". In other words, when your trait A
declares a val
, it means that through a reference of type A
the client can not write this val
, no other guarantees intended, or indeed possible.
P.S. Semicolons are optional in Kotlin, feel free to omit them altogether