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 thatV : ViewModel<PRepo>
, according to the constraints inFrag
.We know that
V: PViewModel<M, R>
, and alsoPViewModel<M, R>: ViewModel<R>
from their respective declarationsTherefore,
V: ViewModel<R>
Even though
R: PRepo
,V: ViewModel<R>
does not implyV: ViewModel<PRepo>
. For this to be true,R
needs to be marked asout
:abstract class ViewModel<out R: Repo>
This prevents you from writing any method/property in
ViewModel
whereR
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
whereR
is in an input position.Alternatively, change the base class of
PFrag
toFrag<R, V>
so thatV : ViewModel<R>
is required, rather thanV : 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.