Reputation: 1802
I have been looking at the paper on the type system of Java and Scala being unsound. To better understand the problem, I have been trying to play around with a smaller related problem.
I have the following types:
class Parent
class Child extends Parent
class Grandchild extends Child
class GrandGrandchild extends Grandchild
Here are some traits with constrained abstract types:
trait LowerBound[T] extends{
type M >: T
}
trait UpperBound[U] extends{
type M <: U
}
I understand that the problem arising here is that the types T
and U
in UpperBound
and LowerBound
are not related. So mixing them can be problematic.
I can see that I can create an object/val by providing the abstract type:
object FamilyMember extends LowerBound[GrandGrandchild] with UpperBound[Parent] {
type M = Child
}
but I fail in defining a trait like the following:
trait FamilyTreeConstraint extends LowerBound[GrandGrandchild] with UpperBound[Parent]
I get:
overriding type M in trait LowerBound with bounds >: A$A131.this.GrandGrandchild; type M in trait UpperBound with bounds <: A$A131.this.Parent has incompatible type
Now if I didn't have any concrete types, the parameterised FamilyConstraint
would be equivalent to:
trait UpperLower[T,U]{
type M >: T <: U
}
on which I understand the error. as T and U are unrelated.
But the Family Constraint type above is not abstract and actually has concrete types. Ie I would have imagined the compiler to end up with this:
trait UpperLowerConcrete{
type M >: GrandGrandchild <: Parent
}
Where I would be allowed to refine M as Child
or GrandChild
.However it doesn't turn into above and gives the same error as the abstract case.
Why?
Also, am I right in thinking that type-refinements are applied first and then type-constraints are checked?
Upvotes: 2
Views: 162
Reputation: 23798
I don't know the reasons for this behavior but from my experience it is often necessary to explicitly override type
definition inside a sub-class/trait if its constraints are changed. What I mean is that once you specify restrictions for M
explicitly in your FamilyTreeConstraint
, the compiler is satisfied
trait FamilyTreeConstraint extends LowerBound[GrandGrandchild] with UpperBound[Parent] {
override type M >: Grandchild <: Parent
}
See it online
Upvotes: 1