This is due not only to the fact that A with B
should be considered as a new type. For a system of type Scala, it does not matter if a class exists corresponding to A with B
An anonymous class is generated because it must contain modal methods for all methods in related attributes.
The reason an anonymous class is created is because the object must have implementations of all methods from A
and all methods from B
At the JVM bytecode level, this would guarantee the inheritance of several classes, and the multiple inheritance model was not supported on the JVM.
To simulate multiple inheritance (or the composition of a mixer, however you want to name it), Scala performs the following actions when creating a trait:
- If the characteristic
T
does not have a method implementation, it creates an interface that defines all the methods in this attribute. If the tag T
has method implementations, it additionally creates the class T$class
, which has a static method for each of the specific methods in T
This static method has the same authority as its corresponding method in T
, but its signature is changed to include the this
parameter. If T
:
def foo(x: Int) = x
then T$class
will have:
<static> def foo($this: T, x: Int) = x
The class obtained by the mixin composition of some class A
and some trait T
will then have a special bridge method generated that forwards the call to the static method that contains the body. Thus, the body of the method is not duplicated in every class that mixes in T
That is why an anonymous class must be created - it must have bridge methods defined for each method in T
Here is an example. When you create a new class by doing mixin composition, for example. calling new A with T
:
class A { def bar = println("!") } trait T { def foo(x: Int) = x } new A with T
the compiler will rewrite it something like this:
class A { def bar = println("!") } <interface> T { def foo(x: Int): Int } class T$class { <static> def foo($this: T, x: Int) = x } class $anon extends A <implements> T {
Note that the compiler can indeed rewrite callites to foo
to invoke static methods directly from callsite, rather than through a bridge method. The reason this is not the case is because then it will no longer support the politicism of the subtypes.
source share