Scala勉強会に行ってきました | Top | 日本語のDjango本が出ます

 

Scalaのtraitを試す

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

Taged with:,,

urihttp://www.everes.net/2008/jun/07/scala-trait/

Entry Date:2008-06-07 22:57

Author:makoto

ping url:http://www.everes.net/2008/jun/07/scala-trait/tbping/

subscribe:feed with LDR

Add Comment

コメント追加








What's Next
Tags
Blog Archive
Project
  • » pymagnolia

    ma.gnolia.comのAPIを操作するPythonライブラリ。

  • » django-ja

    Djangoと日本の仲間たち。
    Djangoに関するニュースや、「仲間たち」のブログエントリをアグリゲートしています。

  • » rhaco

    PHPのWebフレームワーク。 PHPらしさを失わず直感的に記述できることを目指している。 Djangoと同じく、他のライブラリに依存しない。また、Djangoっぽいテンプレートの作り方も可能。

  • » Tracka

    スモールチーム、家族用の知共有ウェブアプリケーション。
    テキスト、画像、youtube動画、stage6動画等をトラック!

  • » BMO

    BMOは、本、CD、DVD、ゲームに印刷されているバーコードをiSightで読み取り、AmazonのAPIを利用して画像や情報をmacに保存します。iSightのついているmacで利用してください。Leopardと呼ばれているOSX 10.5以上が必要です。 保存した情報は、OSX Leopard(10.5)から搭載されたCover FlowとQuick Lookという仕組みを利用して表示します。