I have a trait, which takes a type parameter, and I want to say that the objects that implements this trait will also conform to this type parameter (using generics, for Java’s compatibility)
The following code:
trait HandleOwner[SELF <: HandleOwner[SELF]] {
self : SELF =>
// ...
def handle: Handle[SELF]
}
trait Common[SELF <: Common[SELF]] extends HandleOwner[SELF] {
// ...
}
Gives me the following error:
illegal inheritance; self-type test.Common[SELF] does not conform to
test.HandleOwner[SELF]'s selftype SELF
If I change Common to:
trait Common[SELF <: Common[SELF]] extends HandleOwner[SELF] {
self : SELF =>
// ...
}
Then the error goes away.
Why is it that I have to repeat the same declaration in every non-concrete type. If I would have a base class, and say “extends Comparable”, I don’t have to repeat “extends Comparable” in every derived type, as long as the concrete classes implement the compareTo method. I think it should be the same thing here. I am just saying that a type extending HandleOwner will be also a SELF, and the compiler should just accept it, and take it into consideration while not requiring every non-concrete subtype to repeat the same thing again.
A am doing this to avoid having to use a class-cast, but I will be literally extending every class from this trait, and I don’t see that I should have to repeat this declarations hundreds or even thousands of times!
Self type is more akin to generic constraint than to inheritance. With
class C[A <: B], the constraint must be repeated all along in subclasses :class D[A <: B] extends C[A]. The constraint must be repeated until it is satisfied, that is until you have chosen an actual parameter type which indeed satisfies<: B. Same for the self type. Writingself: A =>does not makes your type extendA. It ensures that it will ultimately have to be mixed in with A before it is actually instantiated.On the opposite, when you extend
Comparable, you have made your class aComparable, not put a constraint for later on. But the fact that you need to implementcompareTohas still to be repeated all along withabstractuntil you actually implement it.Certainly the compiler could do without repeating
<: B,self: A =>, andabstract, the info is available to it. This is language designer choice. At least, having to repeatself: A =>is not different from the rules everywhere else.