Scalaのtraitを試す

2008年06月07日(土) 22:57

さて、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);
    }
}


 
ponybadge

Powered by

Feedbacks

Tweets

Tags

Calendar