Rubyist のための他言語探訪 【第 6 回】 Dylan

著者:まつもとゆきひろ

はじめに

もはや『他言語探訪』というより『出てこいヘンな言語』とでも呼んだほうがよいような方向性の本連載ですが、今月もまたマイナーな言語を紹介します。今月は Dylan です。正直なところ、あまりメジャーな言語は手に余るというか、紹介してて面白くないので、つい誰も知らないような言語を選んじゃうんですよねえ。

Dylan について

さて、Dylan です。Pascal や Ada のように多くのプログラミング言語は人名から名前が取られています。Dylan も Bob Dylan からその名前が取られた……というのは真っ赤な嘘で、本当は、人名と「DYnamic LANguage の略」の両方の意味で Dylan という名前になったのだと聞いています。ただし、人名の方の由来は Bob Dylan ではなく、Dylan Thomas (英国の詩人 1913-1953) なのだそうです。

Dylan は元々 Apple Computer が社内アプリケーション開発用に設計した言語です。正確な時期はわかりませんが 1990 年代の前半頃だと思います。一説によると Apple の PDA である Newton 向けに開発が開始されたのだそうですが、真偽のほどはわかりません。しかし、結局 Dylan の開発は紆余曲折の連続で、Newton の開発には間に合わず (NewtonScript というプロトタイプベースの言語が採用されました)、最初のパブリックリリースが行われた 1995 年時点では Apple はすでに Dylan の開発中止を決定していました。1990 年代初頭に既にアプリケーション開発のための動的言語に注目していた Apple の先見の明に感動すべきなのか、結局すぐれたプログラミング言語に「トドメを刺した」ことを悲しむべきなのかよくわかりません。

Dylan の特徴は

  • Lisp 的セマンティクス
  • Algol っぽい文法
  • マルチメソッド
  • マクロ

などです。最初の二つの項目からもわかるように「Lisp のパワー」と「Algol のなじみやすさ」の共存を目指しています。この二点は Dylan の良さの源泉ともなっていますが、同時に悲運の原因にもなりました。

Lisp と Algol のはざま

当初の Apple の Dylan チームは eval の無い Lisp のような言語を考えていました。eval があると最適化が難しくなり、高速なアプリケーション開発言語にできないことが予想されたからです。また、あくまでもアプリケーション開発用ですから、多くの Lisp とは異なり、開発環境と実行環境の分離が念頭に置かれました。Lisp や Smalltalk では対話的にプログラムを開発して作り上げる「イメージ (プログラムのメモリ状態をダンプしたもの)」がアプリケーションの役割を果たすのですが、これではアプリケーション実行に必要ない開発環境までいつまでも抱え込むことになります。Dylan では、統合開発環境込みの動的な言語でありながら、開発環境と実行環境の間を明確に分離できることを目指していました。

ここまでで十分「筋の良い」言語だと思われるのですが、そうして産声を上げた Dylan に大きな試練が訪れます。それは、「Lisp の多量のカッコは読みにくい」という批判でした。その結果、Dylanチームは恐るべき決断を行います。「Algol 文法を採用しよう」。

その結果、Dylan は (対話的実行よりも) アプリケーション開発を主眼にした Lisp という言語モデルと、Algol っぽい文法の両方を持つ非常に野心的な言語となることが運命づけられました。Dylan のプログラムはたとえば以下のようなものです (以下のサンプルは Dylan programming language - Wikipedia, the free encyclopedia より引用)。

 begin
  let radius = 5;
  let circumference = 2 * $pi *radius;
  if (circumference > 42)
     format-out("Hello, big circle! c = %=", circumference);
  else
     format-out("Hello, circle! c is %=", circumference);
  end if
 end

なんかほのかに Ruby を思い出させますね。クラスは以下のように定義します。

 define class <window> (<view>)
   slot title :: <string> = "untitled", init-keyword: title:;
   slot position :: <point>, required-init-keyword: position:;
 end class;

「slot」というのは要するにインスタンス変数のことで、これは Lisp 方面の用語です。クラス定義はインスタンス変数の宣言しか含みません。この点はメソッドの宣言しか含まない Ruby とは対照的ですね。

ヘンな識別子

上のサンプルプログラムをよく見ると「ヘンな識別子」が登場しています。具体的には「format-out」のようなハイフンを含む関数名と「<window>」のようなクラス名です。普通の Algol 系言語ではこのような識別子は許されませんが、Lisp ではハイフンなど記号を含む識別子はごく普通のことです。ハイブリッドな Dylan はこのような識別子を活かすため「演算子となる記号の前後には必ず空白を必要とする」というルールを導入しました。うっかりすると「a-b」などと書いてしまいそうなので、注意が必要です。

なお、余談ですがクラス名を「<>」でくくるのは Scheme 系オブジェクトシステム (TinyCLOS など) の特徴です。どうやら TinyCLOS は Dylan からこの慣習を受け継いだようです。この点以外にも Dylan は名前空間など Scheme との共通点が多く、実行モデルとしては Common Lisp から CLOS を直接受け継いだというよりも Scheme+CLOS といったイメージです。

Dylan オブジェクトシステム

すでに述べたように Dylan のオブジェクトシステムは (Scheme 経由で) CLOS から受け継いだものですから、Smalltalk、Ruby、Java など広く知られたオブジェクトシステムとは少し違っています。

まず、Dylan には本格的な多重継承があります。このような強力な多重継承機能を持つ言語は、他には CLOS (および他の Lisp 系オブジェクトシステム) や Eiffel くらいしかありません。C++ の多重継承はスーパークラスの優先順位を自動計算する機能がありませんし、Java には仕様の継承しかありません (また、衝突の解消機能もない)、我らが Ruby も多重継承に関してはモジュールの Mix-in という限定した機能しか持っていません (まあ、わざとですが)。

また、それと同時に非常に特徴的であるマルチメソッド (と総称関数) という機能を持っています。多くのオブジェクト指向言語では、メソッドは特定のクラスに所属しています。ところが、Dylan ではメソッドはオブジェクトではなく総称関数という単位でまとめられています。例を見てみましょう。以下は Dylan のメソッド定義です。

 define method turn-blue (w :: <window>)
   ...
 end method;

また、その呼び出しは以下のようになります。

 turn-blue(win)

「なんだ、ただの関数か」と思われるかもしれません。その通りで す。しかし、Dylan の関数は引数の型でオーバーロードします。

 define method turn-blue (b :: <box>)
   ...
 end method;

というメソッドを用意すると、turn-blue 関数は、<window> オブジェクトが与えられたときには <window> 用のメソッドを、<box> オブジェクトが与えられたときには <box> 用のメソッドを起動するポリモルフィックな関数になります。このような複数のメソッドを内包する関数を「総称関数」と呼びます。上の例では引数がひとつしかありませんが、複数の引数が指定されれば、すべての引数のクラスに応じて適用されるメソッドが選択されます。普通のオブジェクト指向言語がレシーバのクラスだけを考慮してメソッドを選択するのとは対照的です。

マクロ

ここまで解説してきたことだけでも十分に野心的なのですが、Dylan チームはさらに野心的な機能を Dylan 言語に組み込みました。それがマクロです。Lisp はプログラムでありデータでもある S 式を操作することによって強力なマクロ機能を持つことで知られていますが、Lisp の影響を大きく受けた Dylan チームが自ら設計する言語にマクロ機能を付けたいと思ったのはごく自然なことです。しかし、単純な S 式を使う Lisp と違って、Algol っぽい文法ではマクロの実現は簡単なことではありませんでした。

Dylan は以下のようなパターンマッチのような方法でマクロを定義します (「Mike Austin’s Blog」から引用)。

 define macro define-method
   { define-method ?class:name . ?name:name (?params:*)
       ?:body
     end } =>
   { define method ?name (?=self :: ?class, ?params)
       ?body
     end }
 end;

これは通常、

 define method move-to (self :: <window>, x, y)
 end;

のように記述される Dylan のメソッド定義を、より「普通」の言語らしく書くための define-method マクロです。このマクロを使うとメソッド定義は以下のようにかけます。

 define-method <window>.move-to(x, y)
 end;

これがうれしいかと聞かれるとなかなか難しいところがありますが (私自身はマクロ懐疑論者ですから)、しかし、プログラムの見かけを大胆に拡張できるマクロはいろいろな局面で強力なツールになる可能性があります。もっとも、マクロは強力であると同時に、プログラムが「わけわか」になる危険性も高いわけですが。

まとめ

なかなか面白く、また鋭い視点から開発が進められた Dylan ですが、既に述べたように開発元の Apple Computer は早々に Dylan から手を引いてしまいました。不幸なことです。

はっきりとした原因がわかる人は誰もいないでしょうが、あえて推測すると、「Lisp の実行モデルと Algol 風文法の融合」、「Algol 風文法におけるマクロの導入」など大胆で野心的な挑戦のため、言語の完成がずるずると遅れてタイミングを失してしまったのが大きな原因のような気がします。

しかし、失われかけた技術にこそ宝が眠っているかもしれません。未来の言語に活かすためにも、また、自分の視野を広げるためにも、今、改めて Dylan を眺めてみるのも面白いかもしれません。間違って復権することがあるかもしれませんし。

Dylan の情報入手先

リンク

Google で検索すると Bob Dylan の情報ばかり登場します。「dylan object」くらいが妥当でしょう。しかし、リンクをたどると 404 (page not found) のページが多いのが悲哀を誘います。

処理系

フリーなものは以下のものがあります。

商用の Dylan については以下を参照してください。

次回予告

オモチャのような言語は紹介したくないので、後は Forth くらいかなあ。そろそろ「ヘンな言語」のネタがつきてきています。ネタがつきた時点で本連載は最終回になりますが、その前に「まつもとにこのヘンな言語を紹介してもらいたい」というようなリクエストは歓迎します。すべてのリクエストに応えられるとは限りませんが。知らない言語は解説できないので。

先日も「Icon を」というリクエストをいただきましたが、実はあまり知らないので躊躇しています。

著者について

matz_in_suit.jpgまつもとゆきひろは自他ともに認める日本を代表する言語オタクです。 言語好きが昂じて自分の言語を設計してしまった大馬鹿者です。 が、オタクとかハッカーとか呼ばれる人種はみんな多かれ少なかれそんなものじゃないでしょうか。

バックナンバー