I have the following problem with hierarchy of traits in Scala code:
First of all, I have a basic trait MyTrait[A]
with such definition:
trait MyTrait[A] {
def v1: A
}
It is then followed by a definition of a trait Base
with a type-member:
trait Base[A] {
type T <: MyTrait[A]
val baseV: T
}
And, at last, a trait Gen
which overrides Base
's type member.
trait Gen[A, X <: MyTrait[A]] extends Base[A] {
type T = X
}
The problem is that in the Gen
trait it seems that bounds of the type-member are lost. This can be proven by following tests:
Compiles:
trait Test1 {
val x: Base[_]
println(x.baseV.v1)
}
Doesn't compile (value v1 is not a member of Test2.this.x.T
):
trait Test2 {
val x: Gen[_, _]
println(x.baseV.v1)
}
I would like to know whether it's a limitation of the language or there is a workaround it. Questions on similar topics on stackowerflow (1, 2) appear to be focusing on different aspects than mine and I am genuinely at a loss because I can't find much information about such behavior in Scala.
Scala code template of this question can be found on scastie
This works:
I believe the issue is that
Has to mean
Which is the same as
That is, even though the bounds on
Gen
say thatX <: MyTrait[A]
, the wildcards do not inherit that bound. You can see a similar problem here:We can add the bounds to the wildcards explicitly. However, because the bound on the second wildcard depends on the first one, we are forced to use the extended
forSome
syntax for the existential, so we can nameA
and use it twice.And I opted to just put everything in the existential clause, which is equivalent:
You can also use
but this is not equivalent, as it doesn't relate the left and right parameters. If
Gen[A, _]
contained anA
in addition to aMyTrait[A]
, then usingx: Gen[_, _ <: MyTrait[_]]
would render the "bare" value and the "wrapped" value with incompatible types.