Maths noob
Maths noob

Reputation: 1802

Scala: Mixing traits with the "same" abstract type member

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.

Upvotes: 2

Views: 162

Answers (1)

SergGr
SergGr

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

Related Questions