2010年5月4日火曜日

Scala DSL

クラウド時代に向けて:

  1. SimpleModel:オブジェクト・メタモデル。クラウド・アプリケーション向けの拡張中。
  2. SimpleModeler:SimpleModelのモデルコンパイラ。
  3. g3:メッセージフロー・フレームワーク。

の開発を行っているわけだけれど、これらの技術のキーテクノロジとなるのがDSL(Domain Specific Language)である。

SimpleModelはメタモデルだけれど、Scala DSLで簡潔に記述できることが要件の一つになっている。そして、SimpleModelのモデルコンパイラがSimpleModeler。SimpleModelerはSimpleModelを記述したScala DSLの集まりをソフトウェアリポジトリとして使用する。

またg3は、Scala DSLで記述したメッセージフロー・モデルに基づいて動作する。

このように、このところはScala DSLを中心に活動しているのだけれど、ここにいたるまで色々と紆余曲折があった。

1998年に登場したXMLがJavaと分散環境のミッシングリンクを埋めるキーテクノロジーであると感じ、Java&XMLを中心に活動していた時期がある。

分散環境では、分散ノード間でのオブジェクトの共有や移送は理論的には不可能ではないにしても相当ハードルが高く、当面は実運用的には不可能と考えてよい、というのが分散OSや分散オブジェクトの教訓。

このため、分散アプリケーションが取るべき現実解は、異機種間での疎結合のサービスを構造化された値の送受信で連携させるということになるのではないか。そしてこの「異機種間で送受信する構造化された値」を記述する技術が当時のJavaには欠けており、ここにXMLはすっぽりとはまるのではないか。

そういったブレークスルーの予感もあって、XMLアプリケーションであるSmartDoc(1998)とRelaxer(2000)を開発したのだけれど、これらのアプリケーションを通して、いわゆる「one source multi use」の有効性を体感することができた。

当時はまだ、DSL(Domain Specific Language)という用語はなかったか、あるいは一般的ではなかったのだけれど、用途ごとの専用言語をXML上に構築して「one source multi use」の運用を行うこと、つまり今の言い方ではDSLが今後の技術の主流になると思えた。

ただ、XMLをDSLのホスト言語として使用することを試行錯誤する中で、XMLは文書をマークアップするにはとても良いのだけれど、定義ファイルやプログラムといった用途に使用するのには向いていないことが分かってきた。

そこで、プログラミング言語をホスト言語にすることを考えたのが次の段階。最初に候補となったのはGroovy。これは2004年頃。Javaベースであり、メタな操作も可能なのでDSLのホスト言語としてうってつけであると思ったわけである。

しかし、いくつか問題があってGroovyを採用するのは断念した。

当時のGroovyは、非常に遅かったのが一点。ただ、こういった問題は時間が解決するので、DSLの用途ではそれほど大きな問題ではない。

木構造を扱う抽象構文的な拡張の柔軟性が低い、という問題もあった。これは、他に良いところがあれば我慢できる範囲。(なにぶん古い話なので今は違った状況になっていると思う。)

しかし、これは大きな問題だと思ったのは、動的言語であるためにDSLの構文にコンパイラ相当のエラーチェックをかけることができない、ということ。これはDSLを使ってモデルを作成していく際の効率を著しく低下させる。

たとえば、フレームワークの設定ファイルに識別子のミススペルがあることが原因で、フレームワークが意味不明のエラーで落ちる、というような事が起きる。

DSL処理系の開発も難しくなる。DSL処理系をクイックハックで作る分には楽でよいのだけれど、本格的なものにしようとするとコンパイラ相当のエラーチェックを自分で実装しなければならなくなる。

そんな中で、アノテーション技術が登場したこともあり、JavaをDSLのホスト言語とすることに決めて開発を進めていた。

しかし、JavaをDSLのホスト言語として使用した場合、メタな情報はjava.lang.reflectionとアノテーションで部分的に取り出すことができるだけなので用途が限られるという問題がある。Javaの文法を構文木として取得するのが非常に難しい。EclipseのASTを使うという案もあったのだけれど、Eclipseに依存してしまうので断念した。

以上のようなこともあり、Javaでは木構造のデータ構造を簡潔に記述するための文法を定義するのが難しい。Javaで書いたロジックをそのまま取り出すことも難しい。

もちろん、GWTのような荒業もあるけれど、これはハードルが高すぎて一般的な技術には成り得ない。

また、Javaではテキスト情報をDSLの一部として記述するのが一苦労。コメントに記述したものを、自作パーサで読み込むといったようなことをやったりしていた。

そして最後に行きついたのがScalaということになる。これが、2008年の7月。

Scalaは、高階関数と字句上の様々なトリックを併用することで、簡潔で強力なDSLを簡単に構築することができる。また、生文字リテラルやXMLリテラルがあるのでテキスト情報の記述も簡単。ケースクラスや抽出子によるリテラル追加機能もよい。しかも、型推論のついた静的型付け言語。

まさに、DSLのために生まれてきた言語である。

たとえば、以前にご紹介したg3フレームワークが使用する以下のScala DSL。Enterprise Integration PatternsのSplitパターンとAggregateパターンを使用したメッセージフローを記述している。これをXMLやJavaで記述しようとすると、大変な事になりそうだ。実装もややこしくなる。

Split.scala
class Split extends G3Application {
  start(List(1, 2, 3, 4, 5)) split() agent {
    case x: Int => x + 100
  } aggregate()
}

しかし、Scalaだととてもすんなりいくのである。実装も、簡単というわけではないけれど、XMLやJavaをDSLにした時のことを考えるとはるかに容易になる。

いずれにしても、こういったDSLの構築技術が、クラウドに限らずこれからのソフトウェア開発のキーテクノロジーになると思っている。よほどの本格的な用途でない限り、ホスト言語の上に構築する内部DSLを使うことになるので、内部DSLが最重要技術ということである。

内部DSLのホスト言語としては、現在のところRuby、Groovy、Scalaが有力だと思われるけれど、やっぱりDSLは静的型付けがよいかな、ということでボクの選択はScalaということになる。もちろん、これは各自の好みで決めてよいところ。DSL処理系の開発効率も重要なので、プログラミングに慣れている言語を選択するのがよいでしょう。

Scala DSLアプリケーションであるSimpleModelerやg3の開発を通して、二年近くScala DSLプログラミングしてきて、多少ノウハウも蓄積されてきた。そのようなこともあり、Scala DSLに関するノウハウを5月18日に行われるJJUG CCCで『Scala DSLの作り方』というセッションで発表させていただけることになった。

興味のある方はぜひどうぞ。

2 件のコメント:

  1. 5月18日に行われるJJUG CCCの『Scala DSLの作り方』を是非聞いてみたいと思います。Ustream配信はありますか?

    返信削除
  2. コメント見逃していました。
    残念ながらUstreamはありません。
    スライドがありますので見てみてください。

    http://www.slideshare.net/asami224/scala-dsl

    返信削除