Traits
//The simplest trait
trait Solver {
def answer(question: String): Int
}
//compiles down to the most borring java interface
public interface Solver {
int answer(String);
}
//traits having some method implementation
trait Solver {
def answer(s: String): Int
def ultimateAnswer =
answer("Answer to the Ultimate Question of Life, the Universe, and Everything")
}
//Still just regular interfacer is generated
public interface Solver {
int answer(java.lang.String);
int ultimateAnswer();
}
//The magic occurs when we extend such trait
class DummySolver extends Solver {
override def answer(s: String) = 42
}
//This is how that class actually looks like
public class DummySolver implements Solver {
public DummySolver() {
Solver$class.$init$(this);
}
public int ultimateAnswer() {
return Solver$class.ultimateAnswer(this);
}
public int answer(String s) {
return 42;
}
}
// A new Solver$class is generated behind the scenes with a bunch of
//static methods.
//This static class receives an instance of the Solver.
//The general scala's patern to implement methods in traits, is to create a helper
//class with static methods and pass in the instance (this) of the class implementing
//the trait -- (kind like implementing OOP manually)
public abstract class Solver$class {
public static int ultimateAnswer(Solver $this) {
return
$this.answer("Answer to the Ultimate Question of Life, the Universe, and Everything");
}
public static void $init$(Solver solver) {}
}
// How fields are implemented?
trait A {
val f1 = 1
}
class B extends TraitWithField
//Is compiled into
public interface A {
public abstract void A$_setter_$f1_$eq(int i);
public abstract int f1();
}
public abstract class A$class {
public static void $init$(A $this){
$this.A$_setter_$f1_$eq(1);
}
}
public class B implements A {
public int f1() {
return f1;
}
public void A$_setter_$f1_$eq(int x$1) {
f1 = x$1;
}
public B() {
A.class.$init$(this);
}
private final int f1;
}