Archive for 10月, 2011

悪い子のためのDart講座〜メソッドを実行時に追加する〜

月曜日, 10月 24th, 2011

いつの間にやら、GoogleからDartという言語が発表されました。
世間の評判を見てみると、一部の方々からは
「無難な感じで刺激が足りない」
「クラスベースが気に食わない。JavaScriptみたいに実行時にプロパティを追加したい」
などといった意見も出ているようです。

そこで本エントリでは、刺激を求める方々のために、
Dartで実行時にメソッドを追加する方法を紹介します。
まずはこちらのコードを御覧ください。

main() {
  var i = new Flexible();
  i.addMethod("plus1", (self, n) { return n + 1; });
  i.addMethod("wawa",
              (self, x, y) {
                return self.plus1(x) + self.plus1(y);
              });
  var x = i.plus1(99);
  print(x);  // => 100
  var y = i.wawa(23, 103);
  print(y);  // => 128
}

実行時にメソッドが追加できているのが確認できます。
これでJavaScript信者の方々も、少しは心やすらぐかと思います。

メソッドaddMethodを持つクラスFlexibleの定義は次のようになっています。

class Flexible {
  var methods;
  Flexible() : methods = new Map();
  addMethod(name, fun) {
    methods[name] = fun;
  }
  noSuchMethod(name, args) {
    if (methods[name] == null) {
      throw new NoSuchMethodException(this, name, args);
    } else if (args.length == 0) {
      return methods[name](this);
    } else if (args.length == 1) {
      return methods[name](this, args[0]);
    } else if (args.length == 2) {
      return methods[name](this, args[0], args[1]);
    }
    throw new NotImplementedException();
  }
}

methodsという変数を用意しておき、コンストラクタで空のMapに初期化します。
addMethodはmethodsに引数で渡された関数を追加するだけです。
noSuchMethodは存在しないメソッドを起動した際に呼ばれる特殊なメソッドで、
ここでaddMethodで追加した関数をディスパッチしてやるという訳です。

パラメータが2つの場合までしか対応していなかったり、
厳密に言えばメソッドを追加しているわけではなかったり、
見れば見るほど卑怯なコードですが、動けばいいんですよ。動けば。

とはいったものの、このコードはstandalone VMでしか動きません。
コンパイラはどうもnoSuchMethodの対応をしていないような気がします。
また、上のソースではnoSuchMethodは2引数ですが、仕様では1引数です。
本当は仕様通り書きたいところですが、それが動く環境がないようなのでやむなしです。
VMのソースを見たら「あとで仕様に合わせる」というコメントが書いてあるので、
そのうち仕様通りに書けば、動くようになってくれるでしょう。

そんなわけで、Dartもその気になれば実行時にメソッドを追加することができます。
皆さんも是非お試しください。おすすめしませんが。