trait

http://twitter.com/#!/kmizu/status/64556087201906688

http://twitter.com/#!/kmizu/status/64556399484612609

とりあえず調べてみました。

m:~/src/scala % cat a.scala b.scala c.scala
trait A { def i = 1 }
class B extends A { }
class C extends A { }
m:~/src/scala % scalac a.scala b.scala c.scala
m:~/src/scala % javap -c A
Compiled from "a.scala"
public interface A extends scala.ScalaObject{
public abstract int i();

}
m:~/src/scala % javap -c B
Compiled from "b.scala"
public class B extends java.lang.Object implements A,scala.ScalaObject{
public B();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."":()V
4: aload_0
5: invokestatic #16; //Method A$class.$init$:(LA;)V
8: return

public int $tag() throws java.rmi.RemoteException;
Code:
0: aload_0
1: invokestatic #23; //Method scala/ScalaObject$class.$tag:(Lscala/ScalaObject;)I
4: ireturn

public int i();
Code:
0: aload_0
1: invokestatic #30; //Method A$class.i:(LA;)I
4: ireturn

}
m:~/src/scala % javap -c C
Compiled from "c.scala"
public class C extends java.lang.Object implements A,scala.ScalaObject{
public C();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."":()V
4: aload_0
5: invokestatic #16; //Method A$class.$init$:(LA;)V
8: return

public int $tag() throws java.rmi.RemoteException;
Code:
0: aload_0
1: invokestatic #23; //Method scala/ScalaObject$class.$tag:(Lscala/ScalaObject;)I
4: ireturn

public int i();
Code:
0: aload_0
1: invokestatic #30; //Method A$class.i:(LA;)I
4: ireturn

}
m:~/src/scala % javap -c A\$class
Compiled from "a.scala"
public abstract class A$class extends java.lang.Object{
public static void $init$(A);
Code:
0: return

public static int i(A);
Code:
0: iconst_1
1: ireturn

}

JVM の仕様を考えれば、結局 trait は interface にするしかなくって、仕方ないのでメソッドの実装はよそにまとめておいて、trait を extends した側で、よそのメソッドを呼んでもらう、という感じになってるんですね…これだと当然 trait にメソッドの追加や削除があった場合に、再コンパイルが無ければ困ったことに。動くことは動くわけですが。