I have the following declarations of classes and traits
class C
class D extends C
trait T extends C
trait U extends D with T
and the following assignments:
val x1:C with T with U = new D with U
val x2:D with T = new C with U
val x3:D with T = new U
val x4:U = new D with T
The first assignment works, the others don't. I want to understand why for both cases.
As far as I understand it, the linearizations are as follows (->
means extends
):
C with T with U
: U -> D -> T -> C
D with U
: U -> T -> D -> C
D with T
: T -> D -> C
C with U
: U -> T -> D -> C
I drew the type hierarchy to get more insight:
My understanding is the following:
x1
: works because the linearized types are the same (the order of D
and T
is not important for the type)x2
: does not work because ...?x3
: Does not work because traits cannot be instantiatedx4
: Does not work because D with T
is a supertype of U
Number 2 is where I'm stuck. It should work IMO because the linearization of D with T
is D -> T -> C
, which is a supertype of the linearization of C with U
(which is U -> T -> D -> C
).
Either my assumption that the order of mixed traits/classes is not important (but then why does the first assignment compile?) or my linearization is wrong or ???
Can you help me on this?
The problem is that new C with U
is not valid; the type of val x2
is not relevant.
The trait U
extends D
which means it can only be applied to a subclasses of D
. Since C
is not a subclass of D
the trait cannot be applied to it.
A trait that extends a class is similar to a self type, but with some subtle differences. See This answer for more information.