uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

Groovy++

ご存知だと思いますがGroovy++というのがあります。(山本さんも記事書いてますLT発表もされています)。

この名を聞くと、Cに対するC++のような、Groovyを拡張した別の言語のように思えますが、違いまして、利用者からすると、「Groovyコードの中で@Typedアノテーションなるものが使えるようになった」というふうに認識した方が実体にあっています。@Typedアノテーションというのは何かというと、メソッド定義に@Typedをつけると、そのメソッドの中のコードでは、

  • メソッド呼び出しの動的ディスパッチ(MetaClass的なもの)が抑制され
  • 静的型に基づいて最適化される
  • (おまけ)静的型に基づいて型チェックされる


ちうものです。この効果は、生成されるコードをJadで逆コンパイルして覗いて見てみますと、圧倒的であることが即座にわかるのでありまして、例えば、今までGroovyで

def g() {
  int result = 0;
  for (int i=0; i<1000000; i++) {
    result += i
  }
}

というコードは

    public Object g()
    {
        Object obj;
        CallSite acallsite[] = $getCallSiteArray();
        Integer result = $const$0;
        for(Integer i = $const$0; ScriptBytecodeAdapter.compareLessThan(i, $const$1);)
        {
            obj = acallsite[1].call(result, i);
            Object _tmp = obj;
            result = (Integer)ScriptBytecodeAdapter.castToType(obj, $get$$class$java$lang$Integer());
            Integer integer = i;
            i = ((Integer) (acallsite[2].call(i)));
            Integer _tmp1 = integer;
        }

        return null;
    }

こういうコードにコンパイルされていたものが、以下のように@Typedをつけると

@Typed
f() {
  int result = 0;
  for (int i=0; i<1000000; i++) {
    result += i
  }
}

よってらっしゃい見てらっしゃい、

    public Object f()
    {
        int result = 0;
        for(int i = 0; i < 0xf4240; i++)
            result += i;

        return null;
    }

こうなるわけです。

おお!!16進数になってる!!←驚くところはそこじゃないダロ*1

まあ、この一事を持ってして、Javaなみに速くなるという事が想像つきます。

もちろん、それによって失われるものもあるでしょうけれども(Groovyっぽくなくなる)、そこは使い分けという事になるでしょうかね。「速くしたいならJavaで書けばいいじゃない」と思われるかもしれませんが、別クラスにしてさらにコンパイルしなければならないJavaと組み合わせるのは、面倒だし配布形態作ったりMavenのpom.xml書いて・・とか遥かに桁違いに厄介になってくるのでよろしくない*2

他には、クロージャのセマンティクスとかも変わっています(クロージャ内から外のローカル変数をアクセスする際にはfinal扱いになるとか。並行処理に有利らしい。将来的にもこのままか、は不明。)。

この機能は私の以前からの望みにごく近い(よっぽど洗練されてますが)もので、ぜひ将来的にはGroovy本体に取り込まれてほしいものです。

ちなみに、@TypedはAST変換でありまして、コードジェネレーションを置き換えるように機能するようですね。

参考:

*1:jadがそう変換してるだけ。念のため。

*2:例えば、どうせ.classにするならgroovy側もgroovycしてまえ、とかいう話になるとスクリプトとしての変更が難しくなったり、そもそもGroovyClassLoaderを介さないことによって動作が変わったり、だからといってスクリプトとClassを混在させると、[http://d.hatena.ne.jp/uehaj/20091208/1260236038:title=面倒な目にあったり]。