※ 商品のリンクをクリックして何かを購入すると私に少額の報酬が入ることがあります【広告表示】 さて、Python温泉ではScalaで動作するLIFTを見てみようと思っていますが、その前にScalaについてもう少し。
このエントリは、OSX(10.5.3)上のScala version 2.7.1.final (Java HotSpot(TM) Client VM, Java 1.5.0_13)を前提としています。core2duoのマシンが欲しいなぁ…
Scala勉強会で気になった機能にtraitという機能があります。 traitはclassに対して機能を追加するような使い方をするもので、定義自体はclassに似ています。
trait BehaviorA{
def hello(name: String) : String = "BehaviorA::" + name
}
Javaは多重継承を禁じていますので、共通機能を複数持ったクラスを作ろうと思うとclassの継承とinterfaceの実装を組み合わせなければなりません。
interface自体は実装を持たないため、同じ名前のメソッドを実装していることを保証するに過ぎないもので、しかも何度も同じような実装を記述しなければなりませんでした。 こんなこと をしようとするとJavaは助長なコードを書かざるを得なかったのです。
traitを使えば、機能の追加はこんな感じに書けます。AnyRefという参照型のボスを継承していますが、ここに本来継承したいクラスがくると考えてください。
バラバラの機能 BehaviorA と BehaviorB を trait として定義しています。
trait BehaviorA{
def hello(name: String) : String = "BehaviorA::hello(" + name
+ ")"
}
trait BehaviorB {
def gooby(name: String) : String = "BehaviorB::gooby(" + name
+ ")"
}
class MainClass extends AnyRef with BehaviorA with BehaviorB {
def test(): String = {
return hello(getClass().getName()) + " and " +
gooby(getClass().getName())
}
}
object Test {
def main(args:Array[String]) : Unit = {
val mc = new MainClass()
println(mc.test())
}
}
このscalaコードをコンパイルし、scala Testと実行すると、以下のように出力します。
BehaviorA::hello(MainClass) and BehaviorB::gooby(MainClass)
実装を持った BehaviorA と BehaviorB の機能を使えるMyClassが出来上がりました。
でも、ちょっと待ってください。Scalaって実はJavaのバイトコードにコンパイルされるんですよ。Javaって多重継承できませんよね?
できあがったclassファイルをjadでデコンパイルしてみました。
デコンパイルされたコードを見て、まず、へぇー、と。なんというかいいですねw
ちなみに、traitは状態も持てます。また「同名のメソッド等を知らないうちに上書きしてしまうのでは?」という恐れに対しては、メソッド等の上書き時にはきちんとoverride宣言をしないとコンパイルエラーとなるといった細やかな気の使い方で、安全にtraitを使用できるようになっています。
以下、デコンパイルしたコード
BehaviorA.jad
import scala.ScalaObject;
public interface BehaviorA
extends ScalaObject
{
public abstract String hello(String s);
}
BehaviorA$class.jad
import scala.StringBuilder;
public abstract class BehaviorA$class
{
public static void $init$(BehaviorA
behaviora)
{
}
public static String hello(BehaviorA $this,
String name)
{
/* 2*/ return (new StringBuilder()).append("BehaviorA::hello
(").append(name).append(")").toString();
}
}
BehaviorB.jad
import scala.ScalaObject;
public interface BehaviorB
extends ScalaObject
{
public abstract String gooby(String s);
}
BehaviorB$class.jad
import scala.StringBuilder;
public abstract class BehaviorB$class
{
public static void $init$(BehaviorB
behaviorb)
{
}
public static String gooby(BehaviorB $this,
String name)
{
/* 6*/ return (new StringBuilder()).append("BehaviorB::gooby
(").append(name).append(")").toString();
}
}
MainClass.jad
import scala.ScalaObject;
import scala.StringBuilder;
public class MainClass
implements BehaviorA, BehaviorB, ScalaObject
{
public MainClass()
{
/* 9*/ BehaviorA.class.$init$(this);
/* 9*/ BehaviorB.class.$init$(this);
}
public String test()
{
/* 11*/ return (new
StringBuilder()).append(hello(getClass().getName())).append(" and
").append(gooby(getClass().getName())).toString();
}
public int $tag()
{
/* 9*/ return scala.ScalaObject.class.$tag(this);
}
public String hello(String x$1)
{
/* 9*/ return BehaviorA.class.hello(this, x$1);
}
public String gooby(String x$1)
{
/* 9*/ return BehaviorB.class.gooby(this, x$1);
}
}
Test$.jad
import scala.Predef$;
import scala.ScalaObject;
public final class Test$
implements ScalaObject
{
public Test$()
{
}
public void main(String args[])
{
/* 17*/ MainClass mc = new MainClass();
/* 18*/ Predef$.MODULE$.println(mc.test());
}
public int $tag()
{
/* 15*/ return scala.ScalaObject.class.$tag(this);
}
public static final Test$ MODULE$ = this;
static
{
new Test$();
}
}
Test.jad
public final class Test
{
public static final int $tag()
{
return Test$.MODULE$.$tag();
}
public static final void main(String args[])
{
Test$.MODULE$.main(args);
}
}