uehaj's blog

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

静的で行こう

Groovy 2.0系では、静的型チェック(STC)の実装がぼちぼち進んでいます(参考過去記事,GEP-8 Static Type Checking)。

さて、もう早速静的型の悪魔に魂を売り払いたい*1、という諸兄におかれましては、「@TypeChecked」というアノテーションを付けるのももどかしいのではないかと思います。

そういう場合は以下のようなWrapperシェルスクリプトを作ると良いと思います(ファイル名は例えばgroovy--with-stc)。

#!/usr/bin/env groovy # -*-groovy-*-

import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.CompilerConfiguration
import groovy.transform.TypeChecked

def configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(new ASTTransformationCustomizer(TypeChecked))
def binding = new Binding()
binding.setVariable("args", args.tail())
def shell = new GroovyShell(binding, configuration)
shell.evaluate(new File(args.head()))

たとえば、こんなファイル"test.groovy"を作って

int i=0

i = "string"

以下のように実行します。

%  groovy--with-stc test.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/Users/uehaj/a.groovy: 3: [Static type checking] - Cannot assign value of type java.lang.String to variable of type int
 @ line 3, column 1.
   i = "string"
   ^

1 error

静的型チェックのエラーになってます(当然Groovy 2.0系以降でないと動きません。)。

class MyClass {
    void foo() {
        hoge()
    }
}

こんなクラス定義(MyClass.groovy)だと

%  groovy--with-stc MyClass.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/Users/uehaj/MyClass.groovy: 9: [Static type checking] - Cannot find matching method MyClass#hoge()
 @ line 9, column 9.
           hoge()
           ^

1 error

おし。

fooは実行されていないのにエラーが検出されていることがポイント。
これベースでflymake-groovyを使えば幸せになれるかも。

あと気付いたんですが、いわゆるBinding変数はSTC配下では使えないみたいですね。従って上ではargsを設定していますが、実際にはアクセスできません*2

GEP-5あたりが実装されれば、もうちょっとスマートになるかもしれません。

*1:本当はSTCはGroovy的な意味で割に保守的です。キャストだらけを避けるための工夫が結構してあります。

*2:static main(String[] args)を定義したクラスであれば引数を受けとれます