One of the use cases for traits mentioned in
Programming in Scala, Odersky et all, Ch. 12.3 is "enriching interfaces".
With this approach
"To enrich an interface using traits, simply define a trait with a small number of abstract methods—the thin part of the trait’s interface—and a potentially large number of concrete methods, all implemented in terms of the
abstract methods. Then you can mix the enrichment trait into a class, implement the thin portion of the interface, and end up with a class that has all of the rich interface available."
The following Scala code is an example:
class Point(val x: Int, val y: Int)
trait Rectangular {
// abstract methods
def topLeft: Point
def bottomRight: Point
def left = topLeft.x
def right = bottomRight.x
def width = right - left
}
class Rectangle(val topLeft: Point, val bottomRight: Point) extends Rectangular {
// other methods...
}
With this setup we can write:
val rect : Rectangular = new Rectangle(new Point(1, 1), new Point(10, 10))
println(rect left) //prints 1
println(rect right) //prints 10
println(rect width) //prints 9
We will now have a peek and the resulting decompiled .class files and see how this magic looks like from the Java point of view (1). The
Point class is unsurprising:
public class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() { return x; }
public int y() { return y; }
}
Things become more interesting with Rectangular. The trait results in two Java classes: Rectangular.java and Rectangular$class.java.
public interface Rectangular {
public abstract Point topLeft();
public abstract Point bottomRight();
public abstract int left();
public abstract int right();
public abstract int width();
}
public abstract class Rectangular$class {
public static int left(Rectangular $this) {
return $this.topLeft().x();
}
public static int right(Rectangular $this) {
return $this.bottomRight().x();
}
public static int width(Rectangular $this) {
return $this.right() - $this.left();
}
public static void $init$(Rectangular rectangular) {}
}
Effectively the trait is broken up into two parts - an interface part (
Rectangular.java) and an implementing class (
Rectangular$class.java) which is not related to Rectangular at all and carries the implemented trait methods as static Java methods.
Finally, the Rectangle class looks like this:
public class Rectangle implements Rectangular {
private final Point topLeft;
private final Point bottomRight;
public Rectangle(Point topLeft, Point bottomRight) {
this.topLeft = topLeft;
this.bottomRight = bottomRight;
Rectangular.class.$init$(this);
}
public Point topLeft() { return topLeft; }
public Point bottomRight() { return bottomRight; }
// the mixin
public int left() { return Rectangular.class.left(this); }
public int right() { return Rectangular.class.right(this); }
public int width() { return Rectangular.class.width(this); }
}
where we see that mixin logic is statically delegated to
Rectangular.
(1)
Compiled with Scala 2.11, decompiled with Jad.