Home > Software design >  Why generic type parent type is not understood by the compiler in parent constructor
Why generic type parent type is not understood by the compiler in parent constructor

Time:06-14

Following code snippet doesn't compile (Kotlin 1.7.0) because in PFrag when calling it's parent (Frag) constructor, V is not recognized as a subtype of ViewModel<PRepo>.
However I think it should because V type is PViewModel<M, R> with PViewModel being a child of ViewModel and R being a child of PRepo.
Is it possible to slighlty modify this code to make it compile (maybe using out keyword) ? Or is it impossible due to some issues I have not yet seen ?

interface Model

abstract class Repo

abstract class ViewModel<R: Repo>

abstract class Frag<R: Repo, V: ViewModel<R>>

interface PModel: Model

abstract class PRepo: Repo()

abstract class PViewModel<M: PModel, R: PRepo>: ViewModel<R>()

abstract class PFrag<M: PModel, R: PRepo, V: PViewModel<M, R>>: Frag<PRepo, V>()

CodePudding user response:

Let's break this down:

  • For Frag<PRepo, V> to work, it must be the case that V : ViewModel<PRepo>, according to the constraints in Frag.

  • We know that V: PViewModel<M, R>, and also PViewModel<M, R>: ViewModel<R> from their respective declarations

  • Therefore, V: ViewModel<R>

  • Even though R: PRepo, V: ViewModel<R> does not imply V: ViewModel<PRepo>. For this to be true, R needs to be marked as out:

    abstract class ViewModel<out R: Repo>
    

    This prevents you from writing any method/property in ViewModel where R is in an input position. You can also do:

    abstract class Frag<R: Repo, V: ViewModel<out R>>
    

    which prevents you from using any members from V where R is in an input position.

  • Alternatively, change the base class of PFrag to Frag<R, V> so that V : ViewModel<R> is required, rather than V : ViewModel<PRepo>:

    abstract class PFrag<M: PModel, R: PRepo, V: PViewModel<M, R>>: Frag<R, V>()
    

Which of those ways is the most suitable depends on your situation. I cannot tell without more information about what these types represent, though I think changing the base class is most likely what you intended.

  • Related