uehaj's blog

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

mixinとMixinアノテーション

いつの間にか(少なくとも1.5.4で確認)(誤認でした。すみませんでした)Groovy 1.6betaあたりから、Groovyにmix-in機能が標準装備されているようです。

Groovyに当初からあったuse文+カテゴリの機能はある意味「メソッド単位のmix-in」だったわけであり、以前紹介した記事のInjectoではuseを使って「クラス単位のmix-in」を実現していたわけですが、1.5.xのどこらへんかで同様にクラス単位のmix-inを標準で使用することができるようになりました。似たものとしてRubyのModuleのinclude、もしくはscalaのtraitsみたいなもの、といえばとおりが良いでしょうかどうでしょうか。

サンプルは以下のとおり。

class HelloMixin {
    static void hello(String s) {
        println "hello $s"
    }
}

String.mixin(HelloMixin)
"world".hello()

使い方としては、インジェクト対象クラスの「mixin」というメソッドの引数にインジェクトしたいクラスを渡します。HelloMixinクラスは、useに渡すカテゴリクラスと同様に、mix-inしたいメソッドをstaticにして第一パラメータをthisと扱うように定義したものです。(この点はInjectoやRubyScalaとは違う。モジュラリティーの単位がクラスと同形ではない。)

以下の様にアノテーションを使うこともできます。

@Mixin(HelloMixin)
class MyClass {
    String toString() { "MyClass" }
}
x = new MyClass()
x.hello()

メリットとしては、確定的な複数メソッドのインジェクト処理をまとめてがばっとできるようになり、また、言語機能としてのMixinと明示できるようになるので可読性・保守性があがる、ってとこですかね。EMC並みの柔軟性は無いでしょうが、その引き換えに、可読性を得る、というか。

上記の情報はテストコード(1,2)のみを参考にしています。