scala2.9でDynamicってやつ入るらしいよ

一昨日の記事で紹介したように、
scala-2.9.0.r24111-b20110127020129
を落としてきて、試してみた



追記:やはりなんだか、色々仕様変わってるみたいなので、そのまま残しておきますが以下はあくまで参考程度に。dynamicのソースも2.9.0RC1がでた2011/3/26日時点では、空になって、コンパイラで特殊処理するようになったみたいだし。
そもそもdynamic自体が、コンパイル時にオプションつけないと働かないようになったようです。あと、みずしまさんによるちょっとした説明



2011/1/28日時点でのDynamicのソース

package scala

/** A trait that supports dynamic invocations. Instances `x` of this trait
 *  allow calls `x.meth(args)` for arbitrary method names `meth` and argument lists
 *  `args`. If a call is not natively supported by `x`, it is rewritten to
 *  `x.invokeDynamic("meth", args)`.
 */
trait Dynamic {

  /** The dynamic invocation operation
   *  @param name  The name of the invoked method
   *  @param args  The arguments to the method
   */
  def invokeDynamic(name: String)(args: Any*): Any

  /** Returns the underlying value typed as an instance of type T
   *  @param T  The target type
   */
  def typed[T]: T
}

自分でテスト用に書いたコード↓

object Main{

  def main(args:Array[String]){
  
    val a:Int = Test.hoge
  
    println(a)
    
    val b:Int = Test.fuga

    println(b)
  }
}

object Test extends Dynamic{

  def invokeDynamic(name:String)(args:Any*):Int = {
  
    name match{
      case "hoge" => 1
      case _      => 0
    }
  }

  def typed[T]:T = {
    null.asInstanceOf[T]
  }
}

色々試した結果、とりあえず上記のコードで、コンパイル通った。
typedっていうMethodをどう定義して使うのかが全くよくわからない(´・ω・`)

で、実行結果は↓

1
0

って感じになります。

コンパイルした結果↓

Main$.jad

import scala.Predef$;
import scala.ScalaObject;
import scala.collection.immutable.Nil$;
import scala.runtime.BoxesRunTime;

public final class Main$
    implements ScalaObject
{

    public void main(String args[])
    {
        int a = Test$.MODULE$.invokeDynamic("hoge", Nil$.MODULE$);
        Predef$.MODULE$.println(BoxesRunTime.boxToInteger(a));
        int b = Test$.MODULE$.invokeDynamic("fuga", Nil$.MODULE$);
        Predef$.MODULE$.println(BoxesRunTime.boxToInteger(b));
    }

    private Main$()
    {
    }

    public static final Main$ MODULE$ = this;

    static 
    {
        new Main$();
    }
}

Main.jad

public final class Main
{

    public static final void main(String args[])
    {
        Main$.MODULE$.main(args);
    }
}

Test$.jad

import scala.Dynamic;
import scala.ScalaObject;
import scala.collection.Seq;
import scala.runtime.BoxesRunTime;

public final class Test$
    implements Dynamic, ScalaObject
{

    public int invokeDynamic(String name, Seq args)
    {
        String s = name;
        s;
        String s1 = "hoge";
        if(s != null) goto _L2; else goto _L1
_L1:
        JVM INSTR pop ;
        if(s1 == null) goto _L4; else goto _L3
_L2:
        s1;
        equals();
        JVM INSTR ifeq 32;
           goto _L4 _L3
_L4:
        1;
          goto _L5
_L3:
        false;
_L5:
        return;
    }

    public Object typed()
    {
        Object _tmp = null;
        return null;
    }

    public volatile Object invokeDynamic(String name, Seq args)
    {
        return BoxesRunTime.boxToInteger(invokeDynamic(name, args));
    }

    private Test$()
    {
    }

    public static final Test$ MODULE$ = this;

    static 
    {
        new Test$();
    }
}

Test.jad

import scala.collection.Seq;

public final class Test
{

    public static final Object typed()
    {
        return Test$.MODULE$.typed();
    }

    public static final int invokeDynamic(String s, Seq seq)
    {
        return Test$.MODULE$.invokeDynamic(s, seq);
    }
}

なんか使い方ちゃんとわかってないので、あとでまた試す(`・ω・´)
しかも、まだ仕様変わる可能性が大きそうですねぇ

追記:コード例がのってるサイト教えてもらった

@xuwei_k もう解決されてしまったかもしれませんが、こちらが参考になりそうです http://bit.ly/iihLHCless than a minute ago via Seesmic Web


他にもいくつか自分でも見つけたのでメモ
http://stackoverflow.com/questions/4709183/practical-uses-of-a-dynamic-type-in-scala
https://gist.github.com/783618/f741175ffcd8dfe333c2da45cf8fdd4d2b134fdb
http://pastie.org/1468102
http://pastie.org/1469213

さらに追記

そもそも、ネット上にあるコード例みると、

_select_
とか
_invoke_
ってメソッド定義して使うみたいですね。(Dynamic継承してる場合、この2つの名前のメソッドは、コンパイラに特別扱いされるっていう感じかな?)

しかし、個人的には、なんかこのやり方がダサい・・・というか、このDynamic型自体、IDEなんかのコード補完の対応なんかが微妙になりそうだし、あまり入ってほしくないような・・・