Kotlin: overriding a common property within a subtype

I am trying to write some general code, but I cannot get rid of the error Type of 'PROPERTY' is not a subtype of the overridden property .

A simplified version of my code:

 abstract class BaseP<V> { var view: V? = null } abstract class BaseF { fun smth() { pp.view = this } abstract val pp: BaseP<BaseF> } abstract class SubF: BaseF() { abstract override val pp: BaseP<SubF> // Error:(20, 30) Type of 'pp' is not a subtype of the overridden property 'public abstract val pp: BaseP<BaseF> defined in BaseF' } 

I found that the error may be @Suppress -ed, but I doubt it is the best and only way. Is there something better?

And in the end, I cannot understand why subtypeA<subtypeB> not considered a subtype of baseA<baseB> , can anyone explain this?

+6
source share
1 answer

Firstly, SubtypeA<B> is a subtype of BaseA<B> , so the problem is subtyping generics parameters.

The answer lies in the Kotlin generic variance , which is similar to what Java .

Why is SubtypeA<SubtypeB> not considered a subtype of BaseA<BaseB> ?

By default, generics are invariant, which means that even in a simpler case, for classes A<T> , A<SubtypeB> and A<BaseB> are not subtypes of each other, unless otherwise specified by dispersion modifiers in and out (or group characters Java ).

Two cases are possible:

  • If you want to take T instances from instances of your class A , you can use the out modifier: A<out T> .

    Here A<SubtypeB> becomes a subtype of A<BaseB> , because from A<SubtypeB> you can obviously take BaseB instances, and not vice versa.

  • If you want to pass only T to the methods of your class, use the in modifier in class declaration: A<in T> .

    And here A<BaseB> is a subtype of A<SubtypeB> , because each instance of A<BaseB> can also take SubtypeB into methods, but not vice versa.

If you both go through and take T to / from your class A<T> , then the only option for T is an invariant, so neither A<SubB> nor A<SuperB> are subtypes of A<B> : otherwise, will lead to a contradiction with the foregoing.

And this is exactly the case: in your BaseP<B> you both take V elements and put them in the view property, so V can only be invariant, and BaseP<SubF> not a subtype of BaseP<BaseF> , it is not SubP<SubF> .

+7
source

All Articles