言語融合の時代
__ かつてプログラミングとは 機械語を人間が直接書くことでした。 その後、いろいろなプログラミング言語が発明されました。 抽象化能力の高い言語を使うと、 「ハードウェアに密着した、ごちゃごちゃした細かいこと」 を気にせずに済むようになりました。 同じ機能が短いコードで実装できるようになり、 生産性が高まりました。 抽象化能力こそが言語のパワーでした。 こうして、プログラミング言語はどんどん抽象化能力を高めてきました。 この時代を便宜的に「第一世代」と呼ぶことにしましょう。
時とともに、価値観は少しずつ変わり始めました。 コンピュータが安価になり、 「一部の研究者が使うもの」ではなくなりました。 プログラマが増えました。 大部分のプログラマの仕事は 「新しいアルゴリズムを作り出して論文を書くこと」ではありませんでした。 「既存の部品を組み合わせてなるべく楽に顧客の望みをかなえること」でした。 高い抽象性よりも、部品(ライブラリ)の充実度や、 開発をサポートするツールの性能が求められるようになりました。 そしてC++やJavaが大きなシェアを持つようになりました。 第一世代のプログラマはこう言います。 「どうしてみんなC++やJavaのような貧弱な言語を使うんだろう。 あれには継続がない、遅延評価がない、カリー化がない、型推論がない…。」 価値観が変わったのです。「第二世代」のプログラマにとって、 充実したライブラリ、高機能な統合開発環境こそが言語のパワーなのです。
今、「第三世代」に向かって、いろいろな変化が起きつつあります。 「デザインパターン」が大流行しました。 再利用するオブジェクトの設計の軸足が継承から委譲へと変わりました。 古いAbstract Windowing Toolkit(AWT)や Swingが部品を継承してカスタマイズさせるのに対し、 新しいStandard Widget Toolkit(SWT)は 部品の継承を禁止していることが象徴的です。 また「依存性の注入」も流行しました。 これはオブジェクトAのオブジェクトBに処理を委譲する場合に、 オブジェクトAがオブジェクトBを作成するのではなく、 「なにものか」がオブジェクトBを作成してオブジェクトAに注入する、 という設計手法です。 この方法を使うとクラスAとクラスBがそれぞれ別個に再利用できるようになります。 依存性の注入は「DIコンテナがXMLで書かれた設定を読んで行う」と書かれることが多いですが、 「JythonがPythonコードを読んで行う」のも同じようなものです。 また2006年9月にはMicrosoftが.NET Framework上で動くPython実装「IronPython 1.0」を、 12月にはSun Microsystemsがスクリプティング標準仕様JSR-223を実装したJava SE6をリリースしました。
第一世代も、第二世代も、使う言語は一つでした。しかし第三世代は 「一つのプログラムに複数の言語を使う」世代です。 5年前に公開されたEclipseが、 今やJavaを使う多くのプロジェクトで当たり前のように利用されているように、 今から5年後には多くのプロジェクトが当たり前のように複数の言語を使っているかも知れません。 「Javaなどの堅い言語で再利用性の高い部品(コンポーネント)を作り、 それをPythonなどのやわらかい言語でつないで使う」、これが基本的な開発方針になっているかもしれません。
筆者は神様ではないので、5年後にどの言語が優位に立っているのかはわかりません。 しかし、現時点ですでにJavaと.NET Frameworkの両方に実装があるPythonは、 他のスクリプト言語から何歩か先に進んでいるのは間違いないでしょう。 この本で学ぶことはきっと無駄にならないはずです。
__ Paul GrahamはBeating the Averagesで「言語の間に順序関係が(全順序ではなく半順序とはいえ)成立する」という仮定を置いています。しかし、これこそ「第一世代」の発想だと思います。 実際にはある言語XとYを考えた場合、文字列処理ならXが便利だけども数値計算にはYが便利、というように得手不得手があるのが普通です。使う目的を限定しなければ半順序さえも成立しません。
Paul Grahamはまた「 「力」とは、 明確に定義できるものではないけれど、たとえば、 ある機能を実現するのに、力の弱い言語では、その機能を含むようなより力の強い言語の インタプリタを書くことでしか実現できない、というふうに言える。」とも言っていますが、 「インタプリタを書くしかない」という考え方こそ第一世代の盲点なのです。 すでに誰かがインタプリタを書いてあるならば、 後はそれをライブラリとして使うだけでその言語の力を獲得できるのです。 第一世代の人には「ライブラリレベルの機能は本質的ではない」という思想があるようですが、第二世代の人にとっては「言語の機能は本質的ではない、ライブラリの多さやIDEの使いやすさが重要」なのです。そして第一世代が軽視し続けた「ライブラリレベルの機能」として、言語の融合が起きつつあるのです。
言語の融合とか、一度に複数の言語を使う、というと「そんなマニアックなことが普及するはずがない」と考える人もいるかも知れません。しかし、すでに自覚せずに複数言語を使っているかもしれませんよ。 正規表現って何でしょうか。 正規表現は命令列ではありません。マッチすべき文字列の形の宣言です。 正規表現ライブラリはプログラマが書いた正規表現を「高速にマッチングできる形」に「コンパイル」します。 Perlの正規表現もJavaの正規表現もほぼ同じ文法です。 そう、正規表現は「文字列マッチングに特化した宣言的プログラミング言語」であり、 正規表現ライブラリは「その言語のコンパイラとVM」なのです。 多くの手続き型言語で、文字列のマッチング処理を書くのは面倒です。ステートマシンを直接書くよりも、解決すべき問題を宣言してそこから自動生成する方が簡単そうです。そこで正規表現という「文字列処理に特化した言語」をライブラリとして組み込んで使っているわけです。多くの異なる言語でほぼ同じ正規表現を使っている事実が、正規表現というものが特定の言語の一部ではなく、独立した言語であることを支持しています。今まで、正規表現がプログラミング言語であるという認識があまりされなかったのは、正規表現が「汎用的なプログラミング言語」ではなく、文字列処理に特化しているからでしょう。
正規表現には限りません。プログラミングの中核が事実上手続き型言語に占められてはいますが、やっぱり世の中には他のパラダイムの方が適している問題領域もたくさんあるわけです。そのため、いろいろな分野で「手続き的ではない」言語が使われています。 分野を限定していたり、小規模な使い方しかしなかったり、手続き型ではないがゆえに手続き型プログラミングに慣れたプログラマにはプログラミング言語に見えにくかったりするだけです。例えばSQL、例えばウェブアプリのテンプレート記述言語。
第三世代の流れは、手続き型の言語に手続き型の言語を組み合わせるというところが今までとはちょっと違いますが、 実際にJythonを使って開発をしていて感じるのは、 やはり「Javaでクラスを宣言しておいて、ロジックはPythonで書く」または 「Pythonで『Javaで書かれたクラスをどういう組み合わせで使うか』を宣言しておいて、ロジックはJavaで書く」というように、どちらかが宣言的な役割を果たすケースが多いということでしょうか。
__ なんだか話の流れで「手続き型と非手続き型で棲み分けが起こる」というストーリーになってしまいましたが、インラインアセンブラとかも複数言語を同時に使っている例ですよね。 「読みやすいけど遅い言語」と「読みにくいけど早い言語」という棲み分けの仕方ですね。
あと、こういうストーリーを書いていると頭の中では「真核生物に好気性細菌が共生してミトコンドリアになり、藍藻が共生して葉緑体になった」というストーリーを連想します。ミトコンドリアもそれ自身のDNAを持っているのですが、ものすごく短いです。なぜかというと、ほとんどの部分は核が持っている情報で用が済むからです。正規表現がシンプルな形でいられるのも、正規表現が他の言語に共生しているからです。正規表現だけでファイルの入出力までできるように正規表現を拡張したとしたら、どれだけ使いにくいものになることやら。そう考えると、将来的には真核生物に相当する「巨大なライブラリを持った手続き型言語」がオルガネラ(細胞内小器官)に相当する「既存のスクリプト言語からいろいろなものをそぎ落とした小さなモジュール」をいくつも持つ形になるのかなぁ、という気がします。
フィードバック
えーと、一応ネイティブな C++ でも(特殊な場面で)遅延評価、(処理系依存の)継続、(限定的な)型推論があります。と弁護してみるてすと。
むしろ、第二世代の人の「言語の機能は本質的ではない、・・・」を適用すると、C++は、正規表現とBNFとPythonとC99より前のCとアセンブリが、ひとつのソースプログラム上で併用可能な言語ということで、晴れて第三世代の仲間入りです。わーい。
第一世代うんぬんは「言語の機能の変化」じゃなくて「プログラマの考え方の変化」ね。C++が第三世代の人にとって「使いものになる言語」の一つであることは間違いないだろうと思います。
僕自身はOCamlを進められるたびに「JavaVM上で動いてPOJOにさわれるなら考えなくもない」と言い続けているのですけど、逆に言えばそれのできない言語は僕にとっては「使えない言語」なのです。