I found a great explanation of how trait is compiled to Java code, but I think it is missing an "abstract override" feature. What Java code is generated for this feature?
1 Answers
Here it comes:
It short, abstract override def m()
allows to call super.m()
from the method and this super call bounds dynamicaly in place of type creation, when a trait is mixing-in after all other types, for example
trait Printer {
def print(msg: String)
}
trait Shouter extends Printer {
abstract override def print(msg: String) { super.print(msg + "!") }
}
class ConsolePrinter extends Printer {
def print(msg: String) { println(msg) }
}
val loudPrinter = new ConsolePrinter with Shouter
loudPrinter.print("Scala is great")
Here we are mixing-in Shouter later, after type linearisation it becomes 'Shouter extends ConsolePrinter', and a call to super.print()
becomesConsolePrinter.print()
and it gives us:
Scala is great!
Google more for "stackable trait pattern", it's a great thing! :)
Agh... I forgot about Java :)
For a given example, we'll have Shouter.class - interface Shouter with methods:
[0] Shouter$$super$print
[1] print
Next, Shouter$class.class - concrete class named "Shouter$class" with static method print(LShouter;Ljava/lang/String;)V
and the body:
0 aload_0
1 new #8 <scala/collection/mutable/StringBuilder>
4 dup
5 invokespecial #12 <scala/collection/mutable/StringBuilder.<init>>
8 aload_1
9 invokevirtual #16 <scala/collection/mutable/StringBuilder.append>
12 ldc #18 <!>
14 invokevirtual #16 <scala/collection/mutable/StringBuilder.append>
17 invokevirtual #22 <scala/collection/mutable/StringBuilder.toString>
20 invokeinterface #28 <Shouter.Shouter$$super$print> count 2
25 return
That is, calling method Shouter$$super$print(String)
on passed instance.
Next, $$anon$1.class
- concrete class named "$anon$1" - this is our new ConsolePrinter with Shouter
. It implements interface Shouter, that is, have it methods implemented. And here:
print(Ljava/lang/String;)V
0 aload_0
1 aload_1
2 invokestatic #21 <Shouter$class.print>
5 return
Shouter$$super$print(Ljava/lang/String;)V
:
0 aload_0
1 aload_1
2 invokespecial #11 <ConsolePrinter.print>
5 return
That is, in called print()
we're calling static Shouter$class.print()
which is an implementation from Shouter trait. That print adds !
and calls Shouter$$super$print() on our object and we forward call to ConsolePrinter.
Here is it.