定義域・値域の詳細指定(もうひとつの「Design by Contract」)

[id:lethevert:20050717:p1]の続きです。
例外処理に対する問題提起から始まって、「Design by Contract」の概念を経て、「定義域・値域の詳細指定」という概念に至ったこの議論を実装するには、いくつかの方法が考えられる。Javaを対象として実装するとすれば、以下の3つの方法がありうる

  1. コンパイラ(javac)を拡張する
  2. プリプロセッサを作成する
  3. 開発環境(eclipseなど)のプラグインに実装する

1つ目の方法は、もっとも自然な言語機能の拡張方法だが、現行のJavaの上に付加機能を一つつけるだけで、コンパイラをすべて作り直すのは、ちょっと面倒だ。しかも、現存する複数のベンダーの手によるJavaコンパイラの一つにしか対応できない(しかも、オープンソースのもの)ので、環境選択の柔軟性も低い。また、Javaコンパイラのソースを追いかけて、そこに機能付加するというのも、手間がかかる。
コンパイラを作り直すよりも、2つ目のようにプリプロセッサで実現する方が、より現実的な解かもしれない。これならば、複数のベンダーのJavaコンパイラに同時に対応できる。拡張されたJavaの文法をに従ってソースをパースして、定義域・値域の指定との矛盾の有無を検査し、矛盾がなければ拡張部分をコメントアウトして、Javaコンパイラに渡すようなやり方でよいだろう。
ただし、1つ目と2つ目に共通して、classファイルレベルで定義域・値域の概念はサポートされていないので、Javaファイルのレベルで定義域・値域のチェックをしなければならない。そのため、プロジェクト単位でコンパイルレベルを統一するような仕組みを導入しなければ、定義域・値域のチェックに穴が生まれてしまう。
そこで、プロジェクトをサポートしている開発環境に実装するという、3つ目の方法が現実的となる。これならば、プロジェクトレベルでの監視を常に行うことができ、チェックの穴の発生を防ぐことができる。ただし、この場合でも、ライブラリなどを利用する場合に、それがclassファイルのみで提供されているときには、チェックを行うことができないので、その点には注意が必要だ。
Javaでプロジェクトをサポートしている開発環境を考えるならば、eclipseに対応するのがベストだろう。おそらく、もっとも普及していて、プラグインも作りやすいと思う。非力なマシン(私の環境など)での動作速度に多少の不安があるけれど。まあ、それは、Javaだから、仕方ないか。
プラグインにするなら、拡張文法としては、Javaコンパイラから見たらコメントアウトされた形での拡張の方がよいと思う。その方が、中間ソースを生成する必要がないため、プラグインの動作を軽くできると思うからだ。そのような観点を考慮した方法としては2つある。

  1. Javadocのコメント内に記法を定義する
  2. Javadocとは別に記法を定義する

Javadocのコメント内に記述する方法は、ドキュメントとの連携も含めて、使い勝手がよいように思う。ただし、ローカル変数に対しては、記述しにくい。
逆に、Javadocとは別に記法を定義すると、記法には柔軟性が生まれる。ローカル変数に対しても定義しやすい。
例として、以下のような記法が考えられる。(Javadocとは別にした例)

int somefunction(int x, int y)
  //!with x | x > 0
  //!with y | y != 0
  //!with return | return > 0
{
  int myVal; //!with myVal | 0 < myVal < 10
  MyClass myObject = new MyClass; //!with myObject | myObject != null
  ...
}