Loading...

100年言語

Original

2003年4月

(このエッセイは、PyCon 2003のキーノートスピーチから派生したものです。)

100年後の生活がどうなっているかを予測するのは難しいです。確実に言えることはほんの少ししかありません。私たちは、誰もが空飛ぶ車を運転し、高層ビルの建設を許可する土地利用規制が緩和され、ほとんどの時間が暗闇に包まれ、女性全員が武術の訓練を受けるだろうということを知っています。ここでは、この絵の中の1つの詳細に焦点を当てたいと思います。これらの空飛ぶ車を制御するソフトウェアを書くために、彼らはどのようなプログラミング言語を使うのでしょうか?

これについて考えるのは、実際にそれらの言語を使えるようになるからではありません。むしろ、私たちが幸運であれば、現時点からその時点までの道のりで使用される言語を使えるようになるからです。

私は、種のように言語も進化の系統樹を形成し、あちこちに行き止まりが分岐していくと考えています。これはすでに起こっていることが見て取れます。 COBOL は、時折の人気にもかかわらず、知的な子孫を持っているようには見えません。それは進化の行き止まり -- ネアンデルタール人の言語 -- なのです。

Javaについても同じような運命が待っていると予想しています。時々、「Javaが成功した言語だと言えないのはなぜですか?すでに成功した言語ですよ」と私にメールを送ってくる人がいます。確かに、本の棚に占める面積や、就職のためにそれを学ばなければならないと信じている学部生の数で測れば、Javaは成功した言語だと言えるでしょう。しかし私が「Javaは成功した言語にはならないだろう」と言っているのは、もっと具体的なことを意味しています。つまり、COBOLのようにJavaも進化の行き止まりになるだろうということです。

これは単なる推測にすぎません。私は間違っているかもしれません。ここで私の目的は、Javaを非難することではなく、進化の系統樹の問題を提起し、「言語Xはその系統樹のどこに位置するのか」と人々に考えてもらうことです。この問題を尋ねる理由は、100年後に「私が言っていたとおりだ」と私の亡霊が言えるようになるためだけではありません。現在のプログラミングに適した言語を見つける上で、主要な枝に近いところにいることが有用なヒューリスティックになるからです。

ある時点では、進化の系統樹の主要な枝にいるのが最も幸せです。ネアンデルタール人がまだ十分にいた時代でも、ネアンデルタール人であることは辛かったはずです。クロマニョン人が絶えず来て、殴り合って食べ物を奪っていたでしょう。

100年後のプログラミング言語がどのようなものになるかを知りたいのは、今どの枝に賭けるべきかを知るためです。

プログラミング言語の進化は、生物種の進化とは異なり、枝が収束することがあります。たとえばFORTRANの枝は、Algolの子孫の枝と合流しつつあるようです。理論的には生物種でも同じことが起こりうるはずですが、細胞以上のものでは起こりにくいでしょう。

言語の場合、収束が起こりやすいのは、可能性の空間が小さいためと、突然変異がランダムではないためです。言語設計者は、他の言語からのアイデアを意図的に取り入れるのです。

プログラミング言語の進化がどのような方向に向かうかを考えることは、言語設計者にとって特に有用です。なぜなら、それに応じて方向性を定めることができるからです。その場合、「主要な枝に留まる」というのは、良い言語を選ぶためのヒューリスティックだけでなく、言語設計における正しい決断のためのヒューリスティックにもなるのです。

どのプログラミング言語も、公理の役割を果たす基本的な演算子のセットと、これらの基本演算子を使って書くことができる残りの部分に分けることができます。

私は、この基本演算子が言語の長期的な生存にとって最も重要な要因だと考えています。残りの部分は変更できます。これは、家を買う際に立地条件を最も重視すべきだという規則に似ています。他のことは後で直せますが、立地は変えられません。

公理が適切に選ばれているだけでなく、できるだけ少ないことが重要だと思います。数学者たちは常に、公理が少ないほど良いと感じてきました。そして、私もそれに同意します。

少なくとも、言語の核心部分を注意深く見て、排除できる公理がないかを確認することは有益な作業だと思います。私の長い怠け者としての経歴の中で、ごみが ごみを生むことを目の当たりにしてきましたし、ソフトウェアの世界でもそれを見てきました。

私の直感では、進化の主要な枝は、核心部分が最も小さく、最もきれいな言語を通っていくのではないかと思います。 自分自身で書くことができる部分が多ければ、その言語はより良いと言えるでしょう。

もちろん、100年後のプログラミング言語について尋ねるという前提自体が大きな仮定です。100年後には、プログラムを書くのではなく、単に私たちの欲しいことをコンピューターに伝えるだけになっているかもしれません。

この分野では、これまで大きな進歩はありませんでした。私の予想では、100年後も、私たちが今日行っているのと同じタイプのプログラムを使ってコンピューターに指示を与えることになるでしょう。プログラムを書かなくても解決できるようになる課題もあるかもしれませんが、私たちが現在行っているようなプログラミングは、相当程度残っていると思います。

100年後の技術の姿を予測することは、傲慢に思えるかもしれません。しかし、私たちには既に50年近くの歴史があることを考えれば、過去50年の言語の進化の遅さを考えると、100年先を展望するのは捉えやすいアイデアだと言えます。

言語は技術ではなく記号体系なので、ゆっくりと進化します。プログラムは、コンピューターに解決してほしい問題を形式的に記述したものです。したがって、プログラミング言語の進化のペースは、交通手段や通信技術ではなく、数学記号の進化に近いのです。数学記号も進化しますが、技術ほど大きな飛躍はありません。

100年後のコンピューターがどのようなものでも、現在よりはるかに高速になることは確実だと予測できます。ムーアの法則が続けば、73,786,976,294,838,206,464倍も高速になるでしょう。それは想像するのが難しいほどです。実際、速度に関する最も可能性の高い予測は、ムーアの法則が機能しなくなることかもしれません。18か月ごとに2倍になるものは、いずれは根本的な限界に達するでしょう。しかし、コンピューターがはるかに高速になることは疑いません。たとえ100倍程度しか高速にならなくても、プログラミング言語の基本ルールを大きく変えるはずです。

その一方で、速度を必要とするアプリケーションもあります。コンピューターによって生み出された問題を解決するためには、高速な処理が必要です。また、画像レンダリング、暗号化、シミュレーションなど、無限に処理能力を必要とする問題もあります。

効率の悪い言語でも使えるようになる一方で、最大限の速度を必要とするアプリケーションも存在するため、プログラミング言語は幅広い効率性をカバーする必要があります。これはすでに起こっていることです。一部の新しい言語の実装は、過去の基準からすると驚くほど無駄が多いのです。

これは言語だけの問題ではありません。技術の進歩に伴い、前世代では無駄だと考えられていたことが当たり前になっていきます。30年前の人々は、今日の長距離電話の使い方に驚くでしょう。100年前の人々は、ボストンからニューヨークまでメンフィスを経由して荷物が運ばれることに、さらに驚くはずです。

今後100年で、高速化したハードウェアが生み出す余剰の処理能力のほとんどは無駄になるでしょう。

私はコンピューターの処理能力が乏しかった時代に プログラミングを学びました。TRS-80の4Kメモリに収まるようBasicプログラムから空白を取り除いたことを覚えています。同じことを繰り返し行う非効率なソフトウェアが膨大な処理能力を消費することは、私には不快に感じられます。しかし、私の直感は間違っているかもしれません。貧しい環境で育った人が、医者に行くなど大切なことにさえ金を使うのを嫌がるのと同じように。

無駄の中には本当に不快なものもあります。SUVなどは、燃料が枯渇せず汚染もしないとしても、不快だと言えるでしょう。SUVは不快な問題の解決策だからです(ミニバンをより男性的に見せるため)。しかし、すべての無駄が悪いわけではありません。長距離通話の時間を数えるのが面倒になるのは、インフラが整備されたからです。リソースがあれば、相手の場所に関係なく通話を一つのことと考えるのがスマートです。

良い無駄と悪い無駄があります。私は良い無駄、つまり、より多くを費やすことで設計をシンプルにできるような無駄に興味があります。新しい高速ハードウェアが生み出す余剰の処理能力をどのように活用できるでしょうか。

私たちの貧弱なコンピューターに染み付いた速度への欲求を克服するには、意識的な努力が必要でしょう。言語設計では、効率性を犠牲にしてでも、わずかな利便性の向上を積極的に追求すべきです。

多くのデータ構造は速度のために存在しています。例えば、多くの言語では文字列とリストが別のデータ型として存在します。意味的には、文字列はリストのサブセットに過ぎません。なぜ別のデータ型が必要なのでしょうか。効率のためだけです。しかし、プログラムを高速に動作させるためのハックで言語の意味論を複雑化するのは愚かです。文字列は言語に存在する必要がないのかもしれません。

言語の核となる部分を公理集合と考えれば、効率性のためだけの追加の公理を設けるのは不適切です。効率性は重要ですが、それを得る適切な方法ではありません。

適切な解決策は、プログラムの意味と実装の詳細を分離することだと思います。文字列とリストを別のデータ型として持つのではなく、リストだけを持ち、必要に応じてコンパイラに文字列を連続したバイトとして配置するための最適化アドバイスを与えるのです。

ほとんどのプログラムでは速度が問題にならないため、このような細かな最適化を行う必要はありません。コンピューターがさらに高速になるにつれ、この傾向はより顕著になるでしょう。

実装の詳細を少なく述べることで、プログラムをより柔軟にすることもできます。仕様は書いている最中に変更されるのは避けられませんが、むしろ望ましいことです。

「エッセイ」という言葉は、フランス語の「essayer」(試みる)に由来します。エッセイとは、何かを理解しようと書くものです。ソフトウェアにもこのような側面があります。最高のプログラムの多くは、作者が最初から正確に何を書こうとしていたわけではないエッセイのようなものだったのかもしれません。

Lispハッカーは、データ構造の柔軟性の価値を知っています。最初のバージョンではすべてをリストで処理し、驚くほど非効率なプログラムを書くことがあります。これは、ステーキを食べるときに、それがどこから来たかを考えないのと同じように、意識的に無視する必要があります。

100年後のプログラマーが求めるのは、最小の労力で信じられないほど非効率なバージョン1のプログラムを作れる言語でしょう。現在の視点から言えば、そうですが、彼らは「プログラミングしやすい言語」と表現するでしょう。

非効率なソフトウェアは問題ではありません。問題なのは、プログラマーに無駄な作業をさせる言語です。プログラマーの時間を無駄にすることが本当の非効率であり、マシンの時間を無駄にすることではありません。これは、コンピューターがさらに高速になるにつれ、より明らかになるでしょう。

文字列を取り除くことは、すでに考えられることだと思います。私たちはArcでそれを行い、それは良いようです。正規表現で表現するのが面倒な操作を、再帰関数で簡単に表現できるのです。

データ構造のこのような平坦化はどこまで進むでしょうか。私の意識的に広げられた心でも驚くような可能性が考えられます。例えば、配列を取り除くことはできるでしょうか。結局のところ、それらはキーがintegerのベクトルであるハッシュテーブルの部分集合にすぎません。ハッシュテーブル自体をリストで置き換えるかもしれません。

それよりも驚くべき可能性もあります。1960年にMcCarthyが記述したLispには、数字がありませんでした。論理的には、数字を別個の概念として持つ必要はなく、リストで表現できます。整数nはn個の要素からなるリストで表現できるのです。この方法で計算することもできます。ただし、途方もなく非効率的です。

実際に数字をリストで実装しようとした人はいませんでした。実際、1960年のMcCarthyの論文は、当時実装する意図ではありませんでした。それは理論的な演習で、チューリングマシンよりも優雅な代替案を作ろうとするものでした。誰かがこの論文を取り上げて、動作するLispインタプリタに翻訳したとき、数字はリストではなく、他の言語と同様にバイナリで表現されていました。

プログラミング言語が数字を基本データ型から取り除くことができるでしょうか。私はこれを真剣な質問というよりは、未来に挑戦するための方法として尋ねています。これは、抗しがたい力と動かしがたい物体が出会う仮想的な場合のようなものです。つまり、想像を絶する非効率な実装と、想像を絶する大きなリソースが出会うのです。私には理由がないように思えます。未来はかなり長いのです。コア言語の公理の数を減らすことができれば、それが無限大に近づくにつれて賭けるべき側だと思います。100年後でも耐えられないと思われるアイデアが、1000年後には受け入れられるかもしれません。

明確にしておきますが、私は数値計算をすべてリストで行うことを提案しているわけではありません。コア言語の定義の中で、このように定義することを提案しているのです。実際のプログラムでは、数値をバイナリで表現するのが最適化であり、コア言語の意味論の一部ではありません。

別の方法として、アプリケーションとハードウェアの間に多層のソフトウェアを設けることが考えられます。これも既に起こっている傾向です。最近の多くの言語がバイトコードにコンパイルされています。ビル・ウッズは、解釈の層が1つ増えるごとに速度が10倍遅くなるというルールを教えてくれました。この余分なコストは柔軟性を生み出します。

Arcの最初のバージョンは、この種の多層の遅さの極端な例で、それに伴う利点もありました。それは、McCarthyの元のLisp論文で定義されたevalのような、クラシックな「メタ循環」インタプリタでした。全体で200行ほどのコードしかなかったので、理解と変更が非常に簡単でした。使用したCommon Lispのインタプリタ、CLispも、バイトコードインタプリタの上で動作していました。つまり、ここには2つの解釈レベルがあり、そのうちの1つ(上位のもの)は驚くほど非効率でしたが、言語は使えました。ぎりぎりまで使えましたが、使えたのです。

アプリケーション内でソフトウェアを複数のレイヤーとして書くのは強力な手法です。ボトムアッププログラミングとは、プログラムを一連のレイヤーとして書くことで、各レイヤーが上位のレイヤーのための言語として機能するというものです。このアプローチは、より小さく柔軟なプログラムを生み出す傾向にあります。また、あの聖杯とも呼ばれる「再利用性」への最良の道でもあります。言語は定義上再利用可能です。アプリケーションの中で、その種類のアプリケーションを記述するための言語に押し込めるものが多ければ多いほど、ソフトウェアの再利用性が高くなります。

somehow、1980年代にオブジェクト指向プログラミングに再利用性が結び付けられ、それに反する証拠があっても、それを振り払うことができません。しかし、オブジェクト指向のソフトウェアの一部が再利用可能であるのは、オブジェクト指向性ではなく、ボトムアップ性によるものです。ライブラリを考えてみると、オブジェクト指向的に書かれているかどうかにかかわらず、それらが言語であるからこそ再利用可能なのです。

ところで、オブジェクト指向プログラミングの衰退は予想しません。優れたプログラマーにとってはあまり魅力的ではありませんが、特定の専門分野を除いては。しかし、大規模な組織にとっては抗いがたいものです。オブジェクト指向プログラミングは、スパゲッティコードを書き続ける持続可能な方法を提供します。それによって、プログラムを一連のパッチとして蓄積することができるのです。

大規模な組織はいつも、このようにソフトウェアを開発する傾向にあり、100年後も同じであると予想します。

未来について話しているのであれば、並列計算についても話さなければなりません。なぜなら、それが未来に存在するように見えるからです。つまり、いつ話しても、並列計算は近い将来に起こるものとして語られます。

未来はそれに追いついてくるでしょうか。並列計算について話されるようになって少なくとも20年は経ちますが、プログラミング実践にはほとんど影響していません。あるいは、そうではないのでしょうか。すでにチップ設計者は並列性を考慮しなければならず、マルチCPUコンピューター上でシステムソフトウェアを書こうとする人々も同様です。

本当の問題は、並列性がどこまで抽象化レベルを上がっていくかということです。100年後には、アプリケーションプログラマーにも影響するでしょうか。それとも、コンパイラライターが考えるものの、アプリケーションのソースコードでは通常見えないものでしょうか。

ただ1つ確実なのは、並列性の機会の大部分が無駄になるだろうということです。これは、与えられた余分なコンピューター性能の大部分が無駄になるという、より一般的な予測の特殊ケースです。ハードウェアの驚くべき速度と同様に、並列性も明示的に要求しない限り使われないものになると予想します。つまり、100年後の並列性は、特殊なアプリケーションを除いて、大規模並列ではなく、プロセスをフォークして並列に実行するようなものになると考えられます。

そして、これは、データ構造の特定の実装を求めるのと同じように、プログラムの寿命の後期に最適化を試みるときに行うことになるでしょう。バージョン1では、並列計算からの利点も、データの特定の表現からの利点も通常無視されます。

特殊な種類のアプリケーションを除いて、並列性は100年後に書かれるプログラムに浸透することはないでしょう。それが浸透していれば、時期尚早の最適化になるでしょう。

100年後にはどれくらいのプログラミング言語があるでしょうか? 最近、新しいプログラミング言語がたくさん登場しているようです。その理由の一部は、より速いハードウェアにより、プログラマーがアプリケーションに応じて速度と利便性のトレードオフを異なるものにできるようになったことです。これが真の傾向であれば、100年後のハードウェアはそれをさらに増大させるはずです。

しかし、100年後には広く使用される言語はわずかしかないかもしれません。私がこう言う理由の一つは楽観主義です。つまり、本当に良い仕事をすれば、遅いバージョン1を書くのに理想的な言語を作ることができ、コンパイラへの適切な最適化アドバイスによって、必要に応じて非常に高速なコードも生成できるはずだと思うのです。そのため、私は楽観的なので、プログラマーが100年後に持つ言語は、許容可能な効率と最大の効率の間の大きな隔たりがあるにもかかわらず、その大部分をカバーできると予想しています。

この隔たりが広がるにつれ、プロファイラの重要性が高まっていくでしょう。プロファイリングにはいまだ十分な注意が払われていません。多くの人々は依然として、高速なアプリケーションを得るには、高速なコードを生成するコンパイラを書くことが重要だと信じています。許容可能な性能と最大の性能の間の隔たりが広がるにつれ、高速なアプリケーションを得るには、その二つを結ぶ良いガイドが必要だということが明らかになっていくでしょう。

言語が少数に限られると述べたとき、ドメイン固有の「小さな言語」は含めていません。そのような埋め込み言語は素晴らしいアイデアだと思い、それらが増えていくことを期待しています。しかし、それらはユーザーが汎用言語の下地を見ることができるような薄いスキンとして書かれるはずです。

未来の言語を設計するのは誰でしょうか? 過去10年間の最も興味深い傾向の1つは、Perl、Python、Rubyのようなオープンソースの言語の台頭です。言語設計がハッカーの手に委ねられつつあります。その結果はごちゃごちゃしていますが、励みになります。Perlには、例えば、驚くべき斬新なアイデアがいくつかあります。多くは驚くほど悪いですが、野心的な試みではそれが常に真実です。現在の変異速度を考えると、Perlが100年後にどのように進化しているかわかりません。

「できないものは教える」というのは真実ではありません(私の知る最高のハッカーの何人かは教授です)が、教える人にはできないことがたくさんあるのは真実です。研究は制限的な身分制度を課します。どの学問分野にも、取り組んでよいトピックと取り組んではいけないトピックがあります。残念ながら、許容されるトピックと禁止されるトピックの区別は、研究論文で説明したときの知的な響きに基づいているのが通例で、良い結果を得るために重要かどうかに基づいているわけではありません。極端な例は恐らく文学でしょう。文学を研究する人々はほとんど、それを生み出す人々に役立つことを言うことはありません。

科学の分野ではより良い状況ですが、許可されている仕事の種類と良い言語を生み出す仕事の種類の重複は嘆かわしいほど小さいです。(Olin Shiversはこれについて雄弁に不平を言っています。)例えば、型は研究論文の無尽蔵の源泉のようですが、静的型付けでは真のマクロを許さないという事実があります。私の意見では、真のマクロがなければ、言語を使う価値はありません。

この傾向は単に、言語がコンパイラ作家ではなくアプリケーションプログラマーによって設計されるようになっているだけでなく、オープンソースプロジェクトとして開発されるようになっているということです。これは良い傾向だと思われ、続いていくと期待しています。

物理学の100年後は予測不可能であるのに対し、原理的には、今から100年後のユーザーに訴求する言語を設計することは可能かもしれません。

言語を設計する1つの方法は、コンパイラが翻訳できるかどうか、ハードウェアが実行できるかどうかにかかわらず、書きたいプログラムをそのまま書き down することです。この方法では、無限の資源を前提とすることができます。今日でも100年後と同様に、無限の資源を想像することができるはずです。

どのようなプログラムを書きたいでしょうか? 最小の労力で書けるものです。ただし、厳密には、現在使用している言語に影響されていなければ最小の労力で書けるものです。そのような影響は非常に広範囲にわたるため、それを乗り越えるのは大変な努力を要します。私たちのような怠け者にとっては、プログラムを最小の労力で表現する方法が明らかであるはずですが、実際には、現在使用している言語によって制限された考え方に囚われているため、より簡単な表現方法は非常に驚くべきものに見えるのです。それは発見しなければならないものであって、自然に思いつくものではありません。

ここで役立つ1つのテクニックは、プログラムの長さを書く労力の近似値として使うことです。文字数ではなく、個別の構文要素の数、つまりパーステツリーのサイズです。最短のプログラムが必ずしも書くのに最小の労力ではないかもしれませんが、簡潔さを目指すのが、曖昧な「最小の労力」よりも良い近似値です。したがって、言語設計のアルゴリズムは、プログラムを見て、それをより短く書く方法はないかを尋ねることになります。

実際に、想像上の100年後の言語でプログラムを書くのは、中核に近いほど上手くいきます。ソートルーチンは今書くことができます。しかし、100年後に必要とされるライブラリの種類を今予測するのは難しいでしょう。おそらく多くのライブラリは、まだ存在していない分野のためのものになるでしょう。例えば、SETI@homeが成功すれば、宇宙人とコミュニケーションをとるためのライブラリが必要になるでしょう。ただし、宇宙人がすでにXMLでコミュニケーションをとっている十分に進化した存在であれば、そうではないかもしれません。

一方、コア言語自体は今設計できるかもしれません。実際、1958年にほぼ設計されていたと主張する人もいるでしょう。

今日の百年言語が利用可能だとしたら、それを使ってプログラミングしたいだろうか? この問題に答えるには過去を振り返るのが一つの方法だ。 1960年代にあった現代のプログラミング言語があったら、誰かが使いたがっただろうか?

いくつかの点では、答えはノーだ。 今日の言語は1960年代にはなかったインフラストラクチャを前提としている。 例えば、Pythonのように字下げが意味を持つ言語は、プリンタターミナルでは上手く機能しなかっただろう。 しかし、そのような問題は脇に置いて-- プログラムはすべて紙に書かれていたと仮定すれば-- 1960年代のプログラマーは、今日使われている言語で書くのを好んでいただろうか?

私は思うに、そうだと思う。 想像力の乏しい一部の人は、初期の言語の特徴が自分らの「プログラム」概念に組み込まれていたため、困難を感じただろう。 (ポインタ演算なしでデータを操作できるだろうか? フローチャートなしでgotoを実装できるだろうか?) しかし、最も賢明なプログラマーは、もし今日の言語を使えていたら、それを最大限に活用できたと思う。

今日百年言語があれば、少なくともすばらしいプソードコードになるだろう。 ソフトウェアを書くのに使うにはどうだろうか? 百年言語は一部のアプリケーションで高速なコードを生成する必要があるので、おそらく現在のハードウェアで十分に実行可能なコードを生成できるはずだ。 百年後の利用者よりも最適化のアドバイスを多く必要とするかもしれないが、それでも全体としては得策かもしれない。

今、(1)百年言語は今日設計できる、(2)そのような言語があれば今日使うのが良いかもしれない、という2つのアイデアがある。 これらを組み合わせると、なぜ今すぐ百年言語を書かないのかという興味深い可能性が浮かび上がる。

言語設計に取り組むときは、そのような目標を持ち、常に意識しておくことが良いと思う。 運転を学ぶ際、道路の縞模様に合わせてフードを合わせるのではなく、遠くの地点を目指すのが正解だと教えられる。 次の10フィートのことしか気にしていなくても、これが正解なのだ。 プログラミング言語でも同じことができると思う。

注記

Lisp Machine Lispが、宣言(動的変数の宣言を除く)は単なる最適化アドバイスであり、正しいプログラムの意味を変えないという原則を体現した最初の言語だと私は信じている。 Common Lispがこれを明示的に述べた最初のものだと思う。

謝辞 Trevor Blackwell、Robert Morris、Dan Giffinの各氏に、このドラフトを読んでいただき、Guido van Rossum、Jeremy Hylton、Pythonチームの皆さんにPyConでの講演の機会を与えていただいたことに感謝する。