Why cannot you override property defined as var with inherited property class?


#1

Hello,

I know that title is hard to understand, so here’s an example of the issue:

open class AbstractB(val param1: String)
class B(param1: String) : AbstractB(param1)

open class AbstractA(open var param: AbstractB)
class A(override var param: B) : AbstractA(param)

So, IntelliJ IDEA says that Var-property type is 'B', which is not a type of overridden
But, if we change class AbstractA param to val the issue doesn’t appear:

open class AbstractB(val param1: String)
class B(param1: String) : AbstractB(param1)

open class AbstractA(open val param: AbstractB)
class A(override val param: B) : AbstractA(param)

Am I missing something?


#2

This results in covariant argument type and leads to type errors. See https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Contravariant_method_argument_type

See this for example:

class B2 : AbstractB("2")
val b1 = B("1")
val b2 = B2()
val a: AbstractA = A(b1) // b2 is incompatible with A() constructor because it requires B not AbstractB
a.param = b2 // b2 is compatible, since a.param is AbstractA.param which is AbstractB

However, b2 is passed to the underlying A.param, which does not accept B2 (B2 extends AbstractB but not B). This leads to type errors.

Therefore, var overrides must always use the same type, while val overrides may use a more specific type.
This is because var generates both a getter (return type) and a setter (argment type), while val only generates a getter (return value).


#3
val a: AbstractA = A()
a.param = AbstractB()  // error: a's real type is A, and its param now has a type of AbstractB, which is not B

#4

I see… The thing with setters makes sense. Now it’s clear. Thank you!