インテンショナルプログラミング
インテンショナルプログラミング(intentional programming)は、プログラミングにおいて、ソースコードにインテンション(意図、意向)を可視化することで、その開発者がそのソースコードにどんな内容を記述したのかをわかりやすくするためのプログラミング手法。インテンションとは、プログラマが構想を練る際に頭の中に生じる概念をさす。プログラマの思考と抽象化のレベルをうまく一致させ、ソースコードの閲覧とプログラムの保守を容易にする。
インテンショナルプログラミングはマイクロソフトに長く勤めたチャールズ・シモニーが提唱した考え方である。彼はマイクロソフトリサーチで、この概念を実証する IP と名づけた統合開発環境の開発を指揮した。理由は不明だが、マイクロソフトはインテンショナルプログラミングに関する作業を止めさせたため、IP の開発は2000年代初期に中止された。
インテンショナルプログラミングに関するよい解説は「Generative Programming: Methods, Tools, and Applications」という本の11章にある。
シモニーの構想によれば、インテンショナルプログラミングのパラダイムを使ったアプリケーションの開発は次のように進められる。プログラマはまず、問題の対象領域(例えば生命保険など)に特化したツールボックスを構築する。次にその領域の専門家がプログラマに協力して、WYSIWYG的手法でアプリケーションがどう動作すべきかを記述する。最後にそのプログラムに関する記述とツールボックスを使って自動化システムが最終的なプログラムを生成する。その後の変更は WYSIWYG レベルでのみ行われ、｢ドメイン・ワークベンチ｣と呼ばれるシステムを利用する。
インテンショナルプログラミングの鍵となる利点(同時に広く普及しない障害でもある)は、ソースコードが単なるテキストファイルではなく、独自のメタな構造を持っている点であり、XML にも似ている。XML と同様、コードの各部に特別な構文解析は不要であり、それらが集まってプログラムが形成される。これにより、記述やツールの修正が容易になる。
エディタとソースコード構造が密接に関連することで、ソースコードへの一種の関係の正規化がなされる。同一性のコンセプトによって、定義や変数名、演算子といったものは常に1つだけ存在するよう格納され、冗長性を排除している。このため、宣言と参照は本質的に区別され、見た目にも明らかになるよう表示される。空白もソースコード内には格納されない。字下げも表示の際に個々のプログラマが設定したとおりに表示される。より進んだ視覚化として、各文を入れ子になった箱のように表示でき、例えばif文を論理回路のように編集したり、名前を他の言語で表示したりといったことが可能である。
ある意味で、C++やJavaのような一般的な言語に XML Schema 的な標準化を行ったようなもので、この環境のユーザーは Eiffel や他の言語のアイデアを組み合わせて利用できる。ドメイン固有言語などの言語指向プログラミングやアスペクト指向プログラミングと同じ文脈で語られることが多い。インテンショナルプログラミングは生成的プログラミングに一種のブレークスルーをもたらすことを意図している。これらの技法により、開発者は言語環境を拡張して領域固有の構成要素を把握でき、その際に新たな言語のためのコンパイラやエディタを一から作る必要がない。
括弧を使用する文法で、1 から 10 までの数を出力するプログラムを書くと、次のようになる。
<pre>
for (int i = 1; i <= 10; i++) {
System.out.println("the number is " + i);
}
</pre>
このコードには多くのコンピュータ言語に必ず存在する制御構造であるループが出てくる。この場合それは for という構文で表されている。これをコンパイルし、リンクして実行すると、10回ループを実行し、ループする度に i がインクリメントされ、表示される。
しかし、このコードではプログラマの「意図; intention」、すなわち「1 から 10 までの数を表示する」ということが伝わらない。このような単純な場合では「意図」が明確化されるよう修正することは簡単だが、そうは行かない場合もある。ループが長大なコードを含んでいる場合、意図を理解するのは難しくなり、特に最初のプログラマが分かり易いコーディングを心がけていない場合には問題はいっそう困難となる。従来、コードの「意図」を示す方法はコメントを追加することだけだったが、必要なものではないため省略されることが多く、そのために改造を重ねるうちに本来の意図とはかけ離れたものになっていくことが多い。
インテンショナルプログラミングでは、上記のループをあるレベルで表現し、そこで「1 から 10 までの数を表示する」という意図が明確化される。システムはその「意図」を使ってソースコードを生成する。生成されるコードは上記のコードとよく似たものになるだろう。つまり、インテンショナルプログラミングでは、ソースコードのレベルにはない意味論的レベルを扱い、大規模なプログラムにおける可読性を劇的に向上させる。
多くの言語には何らかの抽象化を行う手法が備わっているが、インテンショナルプログラミングではLISP系言語のように全く新しい機構を追加していくことができる。従って、最初はC言語のような言語から開発を開始しても、それを拡張していって(新たなコンパイラを待つことなく)C++ のような機能を持たせることができる。これは、クラスやプロシージャよりも強力な拡張機構が使えることを意味する。
インテンショナルプログラミングの中核的概念として同一性がある。多くのプログラミング言語ではソースコードは平坦なテキストであり、オブジェクトは名前で定義/参照され、その同一性はコンパイラが推測するしかない。例えば、ある名前が変数としても、プロシージャ名としても、さらにはデータ型名としても使われることもある。大きなプログラムでは、あるシンボルが実際にはどのオブジェクトを指しているのかを把握するのが非常に困難になる。何かの名前を変更したとき、それに対応してどこを修正しなければならないかは、注意深く調査しなければならない。
対照的に、インテンショナルプログラミングでは、全ての定義には名前が付けられるだけでなく、ユニークな識別子とオブジェクトの対応付けがなされる。従って、変数やプロシージャを参照したとき、名前だけでなくオリジナルの実体に付与された識別子ともリンクされる。
このため、ある実体の名前を変更すると、プログラム内の全ての参照が自動的に更新される。また、別の名前空間で同じ名前を使った場合でも、間違った参照を修正するという作業が不要となる。この機能により、プログラムを各種言語バージョンに移植することも簡単になる。英語の名前群と日本語の名前群を必要に応じて切り換えるなどといったことが簡単にできる。
プログラム内の全ての定義されたオブジェクトにユニークな識別子を付与することで、リファクタリングの自動化や、バージョン管理システムへのコードのチェックインの単純化が容易になる。例えば、共同作業むけのバージョン管理システム(CVSなど)では、2人のプログラマの修正でコンフリクトが生じたとき(例えば、1人がある関数名を変更し、もう1人がその関数の中身を修正した場合)、バージョン管理システムはそれを間違って解釈する可能性がある(1人が新たな関数を定義し、もう1人が古い関数を修正した)。インテンショナルプログラミングでは、同一性が維持されるため、このような誤解が生じない。
インテンショナルプログラミングでは詳細さのレベルを何段階か用意し、プログラマが「ズームイン」したり「ズームアウト」したりできる。例えば上の例では、ズームアウトすると次のような表示となる。
<pre>
<<print>>
</pre>
従って、インテンショナルプログラミングでは自己ドキュメント化が大いに取り入れられており、プログラマはプログラムの高レベルな全体像を容易に把握できる。