uehaj's blog

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

動的型情報に基づく静的型チェックというアイデア(Groovy 2.1リリース記念)

Groovy 2.1がリリースされました。おめでとう! 「Groovy 2.1.0は凄い」で自力で調べた以上の情報がリリースノートには書いてあります。まあ、そうなるわな。

これを記念して、こないだ作った静的型支援ツール「Staticalizer」を、Groovy 2.1.0でより機能強化するためのアイデアを書き残しておきます。

Staticalizerは、実行時の引数やメソッド返り値の型情報を収集し、その型をソースコードにうまく埋め込み戻し、コンパイル時の静的型チェックや静的コンパイルにフィードバックしようと言うものでした。

でもちょっと待って下さい、ソースコードに型を埋め込み戻すなんてことは、必要なんでしょうか?コード、汚れますよね。冗長ですよね。必要悪ですよね。ソースコード上の型情報なんて、IDEが隠蔽してくれて、必要な時だけ表示してくれりゃいいんですがね*1。そう、型推論てのがありますがあれも同じです。型推論が意味するのは「型よ、おめーの存在自体は良いけど、姿は見せるな」というアイデアです。鬼か。

そこで、そう、そうです。そこでGroovy 2.1.0の型チェッカ拡張を使うのです。つまり、Staticalizerと同様に、実行時に型情報を収集します。そして、それを元にしてコンパイル時の静的型チェックをやれば良いのです。

使うイメージとしてはこんな感じ。

  • レコーディングモード。テストケースを実行し、それが結果的にPASSだったら、その実行中に収集された型情報を記録する*2
  • 凍結モード。レコーディングモードで記録した情報に基づいて、以降コンパイルにはその型を元にして静的型チェックが行なわれ、IDEの補完、静的コンパイルにも活かされる。ソースコード表記上は型宣言が無いにもかかわらず、型宣言したのと全く同じように扱われる。
    • 凍結モード状態中に、なんらかの理由で(例えばJVM外部からクラスをロードし、そのコードが新たな型でメソッドを呼び出す場合や、静的型チェックされていないGroovyや、リフレクションでコードが呼び出される場合、Evalされる場合など)で実行時型チェックエラー(クラスキャスト例外やMethodNotFound)が発生し、実行が中止されます。
  • 半凍結モード。「デバッグビルド」の用途で使われ、凍結モードと似ていますが、型チェックエラー発生時には、ダイアログが表示され、「それがコードの誤りによるものか、それとも正しい呼び出しなのか、正しいとしたら、そこでの型チェックは今後もするのか、やめるのか(Objectと扱うのか)」を判別するチャンスが開発者に与えられます。そこで正しいと判定すると、レコーディングモードで設定された条件が緩和されます。それは例えば、def xでxがintかと思っていたら、実はDoubleも受け入れなければならないことが後になって発覚した、というケースで、xはNumberである、Serializableである、Objectである…と範囲を設定します。

というのを、一人ハッカソンで作りたいな…。

ソースコード変更を検出して記録された型情報を適切に捨てたり、静的な型推論情報も追加的に利用したりとかもできると良いね。大変そうだが。

*1:import宣言は多くのIDEで既にそうなってますね。

*2:「レコーディングモードで記録した情報」というのは、Groovy 2.1.0の型チェック拡張のGroovyコードが読み込むデータファイルなどであり、その型チェク拡張コードと共にGroovyプログラムの一部として配布されることになります(おそらくJarに梱包される)。