PR

言語内DSLに向く言語,向かない言語

 まとめてみると,Rubyは非常にDSL向きな言語だと分かります。

 まず,メソッド呼び出しにかっこを省略できることなど表現の多様性により,プログラムを宣言っぽく見せかけることができるので,宣言的な表記が可能になります。DSLで必要とされる機能の多くはデータ構造の表現や,設定など宣言的に表記されることが多く,宣言としての外見を提供できることは重要です。

 さらに,メタプログラミング機能によって,プログラムの情報を取得・更新できるため,DSLに必要な機能をプリプロセッサやマクロを使うことなく実現できます。このように言語を拡張することなくDSLを実現するアプローチを「言語内DSL」と呼んでいます。

 言語内DSLに向いた言語はRubyばかりではありません。Rubyが大きく影響を受けたLispやSmalltalkはRubyと同じように言語内DSLに適しているとされています。特にLispは固定的な文法が原則的にS式という構造データ表現しかありませんから,ほぼ任意の言語内言語を構築可能です。

 Rubyならevalで文字列処理によってプログラムを構築するような局面でも,Lispならマクロによるリスト処理でプログラムを処理できます。Lispのことを「Programmable Programming Language」と呼ぶ人もいるほどです。

 SmalltalkはLispほど極端ではありませんが,Rubyに負けないくらい動的で,かつメタプログラミング機能を持っています。Smalltalkでは元々制御構造もブロックを使って表現しているくらいですから,文法の拡張も思いのままです。

 一方,他の手法を使わないと言語内DSLが実現しにくい言語もあります。例えばC++,Java,C#などの言語ではRuby,Lisp,Smalltalkと同じようなやり方ではDSLを実現できないでしょう。

 しかし,このような言語でもDSLというアプローチを利用できないわけではありません。一つはコード生成です。これはDSLのための「ミニ言語」を用意して,それをC++,Java,C#などのターゲット言語に「コンパイル」するものです。このコンパイルにはしばしばRubyのようなテキスト処理に優れた言語が用いられます。「Code Generation inAction」*4という書籍ではまるまる1冊このテーマが解説されています。

 もう一つのDSLの実現方法はインタプリタを用意するものです。とはいえ,毎回アプリケーションごとに言語を文法から設計・実装するのも大変なので,定型の文法を採用して,ライブラリ・ルーチンを使って読み込みます。

 具体的には文法にXMLを使って,DOM(Document Object Model)などのXML処理ライブラリを使って文法解釈を行います。Javaアプリケーションの設定ファイルにXMLが採用される理由の一つがこれです。XMLファイルによって,いちいちJavaプログラムをコンパイルすることなくアプリケーションの設定を変更したり,挙動をカスタマイズしたりできるようになります。

 このような使われ方をしている場合,XMLはJava界のDSL,あるいはJavaアプリケーションのスクリプト言語と考えることができるでしょう。

 今回はRubyを軸にメタプログラミング機能とその応用,特にDSLについて解説しました。Rubyの機能の応用範囲の広さについて感じていただけたのではないでしょうか。