人気であること
2001年5月
(この記事は新しい言語の事業計画として書かれた。そのため、優れたプログラミング言語の最も重要な特徴である「非常に強力な抽象化」が欠けている(当然のこととしているため)。)
私の友人がかつて著名なオペレーティングシステム専門家に、本当に良いプログラミング言語を設計したいと話したことがある。その専門家は、それは時間の無駄であり、プログラミング言語はその優劣に基づいて人気になったり不人気になったりするものではないため、どれほど良い言語を作っても誰も使わないだろうと言った。少なくとも、それは_彼_が設計した言語に起こったことだった。
何が言語を人気にするのか?人気のある言語はその人気に値するのか?良いプログラミング言語を定義しようと試みる価値があるのか?どうすればそれができるのか?
これらの質問への答えは、ハッカーを見て、彼らが何を求めているかを知ることで見つかると思う。プログラミング言語はハッカー_のためのもの_であり、ハッカーが気に入る場合にのみ、プログラミング言語として(例えば、表示的意味論やコンパイラ設計の演習としてではなく)良いものとなる。
1 人気のメカニズム
確かに、ほとんどの人はプログラミング言語を単にその優劣に基づいて選ぶわけではない。ほとんどのプログラマは、誰か他の人から使うべき言語を指示される。しかし、プログラミング言語の人気に対するそのような外部要因の影響は、時々考えられているほど大きくないと思う。より大きな問題は、良いプログラミング言語に対するハッカーの考えが、ほとんどの言語設計者のそれと同じではないことだと思う。
この2つのうち、ハッカーの意見が重要である。プログラミング言語は定理ではない。それらは人々のために設計されたツールであり、靴が人間の足のために設計されなければならないのと同じくらい、人間の長所と短所に合うように設計されなければならない。靴が履いたときにきついなら、それは悪い靴であり、彫刻作品としてどれほど優雅であろうと関係ない。
ほとんどのプログラマが良い言語と悪い言語を区別できないのかもしれない。しかし、それは他のどんなツールでも同じことだ。だからといって、良い言語を設計しようと試みることが時間の無駄だということにはならない。熟練ハッカーは良い言語を見ればそれが分かり、それを使うだろう。熟練ハッカーは確かにごく少数派だが、そのごく少数派が良いソフトウェアをすべて書き、彼らの影響力は非常に大きいため、他のプログラマは彼らが使う言語を使う傾向がある。実際、それは単なる影響力だけでなく、命令権でもあることが多い。熟練ハッカーは、彼らの上司や教員顧問として、他のプログラマにどの言語を使うべきかを指示するまさにその人物であることが多い。
熟練ハッカーの意見は、プログラミング言語の相対的な人気を決定する唯一の力ではない。レガシーソフトウェア(Cobol)や誇大宣伝(Ada、Java)も役割を果たすが、長期的には最も強力な力だと私は思う。初期の臨界質量と十分な時間があれば、プログラミング言語はおそらくその人気に値するだけの人気を得るだろう。そして、人気は良い言語と悪い言語をさらに区別する。なぜなら、実際のユーザーからのフィードバックは常に改善につながるからだ。人気のある言語がその寿命の間にどれほど変化したかを見てほしい。PerlとFortranは極端な例だが、Lispでさえ大きく変化した。例えば、Lisp 1.5にはマクロがなかった。これらは、MITのハッカーたちが数年間Lispを使って実際のプログラムを書いた後に進化していった。[1]
だから、言語が人気になるために良いものである必要があるかどうかに関わらず、私は言語が良いものであるためには人気である必要があると思う。そして、良い状態を保つためには人気を保つ必要がある。プログラミング言語の最先端は止まらない。しかし、今日私たちが持っているLispは、1980年代半ばにMITにあったものとほとんど同じだ。なぜなら、それがLispが十分に大きく、要求の厳しいユーザー層を持っていた最後の時期だからだ。
もちろん、ハッカーは言語を使う前にその存在を知る必要がある。どうやって知るのか?他のハッカーからだ。しかし、他のハッカーがその言語について聞くためにも、その言語を使っている初期のハッカーのグループが必要だ。このグループがどれくらいの規模である必要があるのか、どれくらいのユーザーが臨界質量を形成するのか、私は疑問に思う。ざっと考えて、20人だろう。もしある言語に20人の独立したユーザー、つまり自らの意思でそれを使うと決めた20人のユーザーがいれば、私はそれを本物だと考えるだろう。
そこに到達するのは簡単ではないだろう。ゼロから20人に到達する方が、20人から1000人に到達するよりも難しいとしても驚かない。最初の20人のユーザーを獲得する最善の方法は、おそらくトロイの木馬を使うことだろう。つまり、人々が欲しがるアプリケーションを提供し、それがたまたま新しい言語で書かれているという形だ。
2 外部要因
プログラミング言語の人気に影響を与える一つの外部要因を認めるところから始めよう。人気になるためには、プログラミング言語は人気のあるシステムのスクリプト言語である必要がある。FortranとCobolは初期のIBMメインフレームのスクリプト言語だった。CはUnixのスクリプト言語であり、後にPerlもそうだった。TclはTkのスクリプト言語だ。JavaとJavascriptはウェブブラウザのスクリプト言語となることを意図されている。
Lispが絶大な人気を誇る言語ではないのは、それが絶大な人気を誇るシステムのスクリプト言語ではないからだ。Lispが保持している人気は、1960年代と1970年代にMITのスクリプト言語だった時代に遡る。当時の多くの偉大なプログラマは、ある時点でMITと関係があった。そして、1970年代初頭、Cが登場する前は、MITのLisp方言であるMacLispは、真剣なハッカーが使いたがる唯一のプログラミング言語の一つだった。
今日、LispはEmacsとAutocadという2つのそこそこ人気のあるシステムのスクリプト言語であり、そのため、今日行われているLispプログラミングのほとんどはEmacs LispまたはAutoLispで行われていると私は推測する。
プログラミング言語は孤立して存在するわけではない。ハックするは他動詞であり、ハッカーは通常何かをハックしている。そして実際には、言語はそれがハックするために使われるものと比較して判断される。だから、人気のある言語を設計したいなら、言語以上のものを提供するか、既存のシステムのスクリプト言語を置き換えるように言語を設計する必要がある。
Common Lispが不人気なのは、部分的にそれが孤児だからだ。元々はハックするためのシステム、Lispマシンと共に出てきた。しかし、Lispマシン(並列コンピュータと共に)は、1980年代の汎用プロセッサの性能向上によって圧倒された。Common Lispは、Unixの良いスクリプト言語であったなら、人気を保っていたかもしれない。残念ながら、それはひどく悪いものだ。
この状況を説明する一つの方法は、言語がそれ自体の優劣で判断されないと言うことだ。別の見方は、プログラミング言語は、何かのスクリプト言語でもあるのでなければ、本当のプログラミング言語ではないということだ。これは、それが驚きとして受け止められる場合にのみ不公平に思える。私は、プログラミング言語に実装があることを期待するのと同様に、不公平ではないと思う。それはプログラミング言語の一部なのだ。
もちろん、プログラミング言語には良い実装が必要であり、これは無料である必要がある。企業はソフトウェアにお金を払うが、個々のハッカーは払わない。そして、あなたが惹きつける必要があるのはハッカーなのだ。
言語には、それについての本も必要だ。その本は薄く、よく書かれていて、良い例が豊富にあるべきだ。K&Rが理想だ。現時点では、言語はO'Reillyから出版された本を持っている必要があるとさえ言えるだろう。それがハッカーにとって重要であることの試金石になりつつある。
オンラインドキュメントも必要だ。実際、本はオンラインドキュメントとして始めることができる。しかし、私は物理的な本がまだ時代遅れだとは思わない。その形式は便利であり、出版社によって課される事実上の検閲は、不完全ながらも有用なフィルターだ。書店は新しい言語について学ぶための最も重要な場所の一つだ。
3 簡潔さ
どんな言語にも必要な3つのもの、つまり無料の実装、本、そしてハックする何かを提供できるとして、ハッカーが気に入る言語をどうやって作るのか?
ハッカーが好むものの一つは簡潔さだ。ハッカーは、数学者やモダニズム建築家が怠惰であるのと同じ意味で怠惰だ。彼らは余計なものを嫌う。プログラムを書こうとしているハッカーが、少なくとも無意識のうちに、入力しなければならない文字の総数に基づいて使う言語を決定すると言っても、真実から遠くないだろう。もしこれがハッカーの考え方と正確に一致しないとしても、言語設計者はそうであるかのように振る舞うべきだ。
英語に似せようとする冗長な表現でユーザーを甘やかすのは間違いだ。Cobolはこの欠点で悪名高い。ハッカーは、
add x to y giving z
の代わりに
z = x+y
を書くように求められることを、自分の知性への侮辱と神への冒涜の中間にあるものと見なすだろう。
Lispはcarとcdrの代わりにfirstとrestを使うべきだと言われることがある。そうすればプログラムが読みやすくなるからだ。最初の数時間だけかもしれない。しかし、ハッカーはcarがリストの最初の要素を意味し、cdrが残りを意味することをすぐに学ぶことができる。firstとrestを使うと、タイピングが50%増える。そして、それらは長さも異なるため、carとcdrが連続する行でよく呼び出されるように、引数が揃わないことになる。私は、コードがページ上でどのように揃うかが非常に重要だと感じている。可変幅フォントで設定されたLispコードはほとんど読めないし、友人も他の言語でも同じだと言っている。
簡潔さは、強い型付け言語が劣る点の一つだ。他のすべての条件が同じであれば、誰もプログラムを大量の宣言で始めたいとは思わない。暗黙的になり得るものは、すべてそうあるべきだ。
個々のトークンも短いべきだ。PerlとCommon Lispはこの問題に関して正反対の極にある。Perlプログラムはほとんど暗号のように密になり得るが、Common Lispの組み込み演算子の名前は滑稽なほど長い。Common Lispの設計者はおそらく、ユーザーがこれらの長い名前を自動入力してくれるテキストエディタを持っていると期待したのだろう。しかし、長い名前のコストは、それを入力するコストだけではない。それを読むコスト、そして画面上のスペースを占めるコストもある。
4 ハックしやすさ
ハッカーにとって簡潔さよりも重要なことが一つある。それは、やりたいことができることだ。プログラミング言語の歴史において、プログラマが不適切だと見なされることをするのを防ぐために、驚くほどの努力が費やされてきた。これは危険なほど傲慢な計画だ。言語設計者がプログラマが何を必要とするかを知ることができるだろうか?言語設計者は、ユーザーを自分自身から保護される必要がある不器用な人ではなく、彼らが決して予期しなかったことをする必要がある天才と見なすべきだと思う。不器用な人はどうせ自滅するだろう。あなたは彼が別のパッケージの変数を参照するのを防ぐことはできるかもしれないが、間違った問題を解決するためにひどく設計されたプログラムを書き、それに永遠に時間をかけるのを防ぐことはできない。
良いプログラマはしばしば危険で好ましくないことをしたがる。好ましくないこととは、言語が提示しようとしている意味論的な見せかけの裏側にあること、例えば、高レベル抽象化の内部表現を手に入れることなどを意味する。ハッカーはハックするのが好きであり、ハックするとは物事の内部に入り込み、元の設計者の意図を覆すことを意味する。
設計者の意図を覆されることを許容せよ。 どんなツールを作っても、人々はあなたが意図しなかった方法でそれを使う。そして、プログラミング言語のような高度に体系化されたツールでは特にそうだ。多くのハッカーは、あなたが想像もしなかった方法であなたの意味論モデルを微調整したいと思うだろう。私は彼らにそうさせるべきだと言う。ガベージコレクタのようなランタイムシステムを危険にさらすことなく、可能な限り多くの内部的なものにプログラマがアクセスできるようにするのだ。
Common Lispでは、構造体のフィールドを反復処理したいとよく思った。例えば、削除されたオブジェクトへの参照を取り除いたり、未初期化のフィールドを見つけたりするためだ。構造体が内部的には単なるベクトルであることは知っている。しかし、どんな構造体にも呼び出せる汎用関数を書くことはできない。フィールドには名前でしかアクセスできない。なぜなら、それが構造体が意味するものだからだ。
ハッカーは、大きなプログラムの中で、意図されたモデルを覆したいと一度か二度しか思わないかもしれない。しかし、それができることによってどれほどの違いが生まれることか。そして、それは単に問題を解決する以上の問題かもしれない。ここにはある種の喜びもある。ハッカーは、外科医がぞっとするような内臓をいじる秘密の喜び、ティーンエイジャーがニキビを潰す秘密の喜びを共有している。[2] 少なくとも少年たちにとっては、ある種の恐怖は魅力的だ。Maxim誌は毎年、ピンナップと恐ろしい事故の写真を混ぜた写真集を出版している。彼らは自分たちの読者を知っているのだ。
歴史的に、Lispはハッカーがやりたいようにさせるのが得意だった。Common Lispの過度な規範性は逸脱だ。初期のLispはあらゆるものに手を出すことを許した。幸いなことに、その精神の多くはマクロに保存されている。ソースコードに任意の変換を施すことができるとは、なんて素晴らしいことだろう。
古典的なマクロは真のハッカーのツールだ。シンプルで、強力で、危険だ。それらが何をするかを理解するのはとても簡単だ。マクロの引数に関数を呼び出し、それが返すものがマクロ呼び出しの代わりに挿入される。ハイジェニックマクロは正反対の原則を体現している。それらはあなたがそれらが何をしているかを理解するのを妨げようとする。私はハイジェニックマクロが1文で説明されたのを聞いたことがない。そして、それらはプログラマが何を望むことを許されるかを決定することの危険性の典型的な例だ。ハイジェニックマクロは、特に変数キャプチャから私を保護することを意図しているが、変数キャプチャはまさに私が一部のマクロで望むものなのだ。
本当に良い言語は、クリーンかつダーティであるべきだ。つまり、よく理解され、高度に直交する演算子の小さなコアを持つクリーンな設計でありながら、ハッカーがやりたいようにできるという意味でダーティであるべきだ。Cはそうだ。初期のLispもそうだった。真のハッカー向け言語は常に、やや粗野な性格を持つだろう。
良いプログラミング言語は、「ソフトウェア工学」というフレーズを使うような人々が不満げに首を振るような特徴を持つべきだ。その連続体の反対側には、AdaやPascalのような言語がある。これらは規範の模範であり、教育には良いが、それ以外にはあまり役に立たない。
5 使い捨てプログラム
ハッカーにとって魅力的であるためには、言語は彼らが書きたい種類のプログラムを書くのに適している必要がある。そしてそれは、おそらく驚くべきことだが、使い捨てプログラムを書くのに適している必要があることを意味する。
使い捨てプログラムとは、ある限られたタスクのために素早く書くプログラムのことだ。例えば、システム管理タスクを自動化するプログラム、シミュレーション用のテストデータを生成するプログラム、ある形式から別の形式へデータを変換するプログラムなどだ。使い捨てプログラムの驚くべき点は、第二次世界大戦中に多くのアメリカの大学で建てられた「仮設」の建物のように、しばしば捨てられないことだ。多くは、実際の機能と実際のユーザーを持つ実際のプログラムへと進化する。
最高の大きなプログラムは、フーバーダムのように最初から大規模に設計されるのではなく、このようにして誕生するという直感がある。ゼロから大きなものを作るのは恐ろしいことだ。人々が大きすぎるプロジェクトに着手すると、圧倒されてしまう。プロジェクトは行き詰まるか、結果は無味乾燥で硬直したものになる。本物の繁華街ではなくショッピングモール、ローマではなくブラジリア、CではなくAdaのように。
大きなプログラムを得るもう一つの方法は、使い捨てプログラムから始めて、それを改善し続けることだ。このアプローチはそれほど気が遠くならず、プログラムの設計は進化の恩恵を受ける。もし調べてみれば、ほとんどの大きなプログラムがこのように開発されたことがわかるだろう。そして、このように進化したプログラムは、政治的な理由を除いてプログラムが移植されることは稀であるため、おそらく最初に書かれた言語で書かれたままだろう。したがって、逆説的に、大規模なシステムに使われる言語を作りたいなら、使い捨てプログラムを書くのに適した言語にする必要がある。なぜなら、大規模なシステムはそこから生まれるからだ。
Perlはこのアイデアの顕著な例だ。それは使い捨てプログラムを書くために設計されただけでなく、それ自体がほとんど使い捨てプログラムだった。Perlはレポート生成のためのユーティリティ集として誕生し、人々がそれで書いた使い捨てプログラムが大きくなるにつれて、プログラミング言語へと進化していった。Perl 5(もしそうなら)になるまで、その言語は本格的なプログラムを書くのに適していなかったが、それでもすでに絶大な人気を誇っていた。
何が言語を使い捨てプログラムに適したものにするのか?まず、すぐに利用可能である必要がある。使い捨てプログラムは、1時間で作成することを期待するようなものだ。だから、その言語は、あなたが使っているコンピュータにすでにインストールされている必要があるだろう。使う前にインストールしなければならないものであってはならない。そこにあるべきなのだ。Cはオペレーティングシステムに付属していたからそこにあった。Perlは元々システム管理者向けのツールであり、あなたのシステム管理者がすでにインストールしていたからそこにあったのだ。
しかし、利用可能であることは、インストールされていること以上の意味を持つ。コマンドラインインターフェースを持つ対話型言語は、個別にコンパイルして実行しなければならない言語よりも利用しやすい。人気のあるプログラミング言語は対話型であり、起動が速いべきだ。
使い捨てプログラムで望むもう一つのことは簡潔さだ。簡潔さは常にハッカーにとって魅力的であり、1時間で作成することを期待するプログラムではなおさらだ。
6 ライブラリ
もちろん、究極の簡潔さは、プログラムがすでに書かれていて、それを呼び出すだけで済むことだ。そして、これはプログラミング言語のますます重要な特徴となるであろうもの、つまりライブラリ関数へと私たちを導く。Perlが勝つのは、文字列操作のための大規模なライブラリを持っているからだ。この種のライブラリ関数は、データの変換や抽出のために元々書かれることが多い使い捨てプログラムにとって特に重要だ。多くのPerlプログラムは、おそらくいくつかのライブラリ呼び出しを組み合わせたものとして始まるだろう。
今後50年間でプログラミング言語に起こる進歩の多くは、ライブラリ関数に関係するだろうと私は思う。将来のプログラミング言語は、コア言語と同じくらい注意深く設計されたライブラリを持つだろうと私は思う。プログラミング言語の設計は、言語を強い型付けにするか弱い型付けにするか、オブジェクト指向にするか関数型にするかなどではなく、素晴らしいライブラリをどう設計するかになるだろう。「ソフトウェア工学」というフレーズを使うような言語設計者は、これに身震いするかもしれない。まるでアプリケーションを書くようなものだからだ!残念だが。言語はプログラマのためのものであり、ライブラリはプログラマが必要とするものなのだ。
良いライブラリを設計するのは難しい。それは単に多くのコードを書くことではない。ライブラリが大きくなりすぎると、必要な関数を見つけるのに自分でコードを書くよりも時間がかかることがある。ライブラリは、コア言語と同じように、少数の直交する演算子を使って設計される必要がある。プログラマが、どのライブラリ呼び出しが何を必要とするかを推測できるべきなのだ。
ライブラリはCommon Lispが劣っている点の一つだ。文字列操作のための初歩的なライブラリしかなく、オペレーティングシステムと対話するためのものはほとんどない。歴史的な理由から、Common LispはOSが存在しないふりをしようとする。そして、OSと対話できないため、Common Lispの組み込み演算子だけを使って本格的なプログラムを書くことはまずできないだろう。実装固有のハックも使う必要があり、実際にはこれらはあなたが望むすべてを提供してくれるわけではない。もしCommon Lispに強力な文字列ライブラリと優れたOSサポートがあれば、ハッカーはLispをはるかに高く評価するだろう。
7 構文
Lispの構文、より正確には構文の欠如を持つ言語が、人気になることはあるだろうか?この質問の答えは分からない。しかし、構文がLispが現在人気がない主な理由ではないと私は思う。Common Lispは馴染みのない構文よりも悪い問題を抱えている。私は前置構文に慣れているプログラマを何人か知っているが、彼らは強力な文字列ライブラリを持ち、OSと対話できるため、デフォルトでPerlを使っている。
前置記法には2つの問題が考えられる。プログラマにとって馴染みがないことと、十分に密ではないことだ。Lispの世界の一般的な見解では、最初の問題が本当の問題だとされている。私はそうは思わない。確かに、前置記法は普通のプログラマをパニックにさせる。しかし、普通のプログラマの意見は重要ではないと思う。言語は熟練ハッカーがそれらをどう評価するかに基づいて人気になったり不人気になったりする。そして、熟練ハッカーは前置記法に対処できると思う。Perlの構文はかなり理解しにくいが、それがPerlの人気を妨げることはなかった。むしろ、Perlカルトを育むのに役立ったかもしれない。
より深刻な問題は、前置記法の冗長性だ。熟練ハッカーにとっては、それは本当に問題だ。a[x,y]
と書けるのに、誰も(aref a x y)
と書きたがらないだろう。
この特定のケースでは、問題を巧みに回避する方法がある。データ構造をインデックス上の関数であるかのように扱えば、代わりに(a x y)
と書くことができ、これはPerl形式よりもさらに短い。同様のトリックで他の種類の式も短縮できるかもしれない。
インデントを意味のあるものにすることで、多くの括弧を取り除く(またはオプションにする)ことができる。プログラマはとにかくコードをそのように読んでいる。インデントがあることを示し、区切り文字が別のことを示す場合、私たちはインデントに従う。インデントを意味のあるものとして扱うことで、この一般的なバグの原因を排除し、プログラムを短縮できるだろう。
中置構文の方が読みやすい場合もある。これは特に数式に当てはまる。私はプログラミング人生のすべてをLispで過ごしてきたが、それでも前置数式が自然だと感じない。しかし、特にコードを生成する際には、任意の数の引数を取る演算子があるのは便利だ。だから、もし中置構文を持つなら、それは何らかのリードマクロとして実装されるべきだろう。
Lispに構文を導入することに、それが基盤となるS式にうまく理解できる形で変換される限り、宗教的に反対すべきではないと思う。Lispにはすでにかなりの構文がある。誰も強制されない限り、さらに導入することは必ずしも悪いことではない。Common Lispでは、一部の区切り文字が言語のために予約されており、少なくとも一部の設計者が将来より多くの構文を持つことを意図していたことを示唆している。
Common Lispで最もひどくLispらしくない構文の一つは、フォーマット文字列に現れる。formatはそれ自体が言語であり、その言語はLispではない。もしLispにさらに構文を導入する計画があったなら、フォーマット指定子もそれに含めることができたかもしれない。マクロが他の種類のコードを生成するのと同じようにフォーマット指定子を生成できれば、それは良いことだろう。
ある著名なLispハッカーが、彼のCLTLのコピーはフォーマットのセクションで開くと私に言った。私のものもそうだ。これはおそらく改善の余地があることを示している。また、プログラムが多くのI/Oを行うことを意味するのかもしれない。
8 効率性
誰もが知っているように、良い言語は高速なコードを生成すべきだ。しかし実際には、高速なコードは主に言語の設計で行うことから生まれるものではないと私は思う。Knuthがずっと前に指摘したように、速度は特定の重要なボトルネックでのみ重要だ。そして、多くのプログラマがそれ以来観察しているように、これらのボトルネックがどこにあるかについて誤解していることが非常に多い。
だから、実際には、高速なコードを得る方法は、例えば言語を強い型付けにするのではなく、非常に優れたプロファイラを持つことだ。プログラム内のすべての呼び出しですべての引数の型を知る必要はない。ボトルネックで引数の型を宣言できる必要がある。そしてさらに、ボトルネックがどこにあるかを見つけられる必要がある。
Lispについて人々が抱いていた不満の一つは、何がコストがかかるのか分かりにくいということだ。これは真実かもしれない。また、非常に抽象的な言語を持ちたいなら、避けられないことかもしれない。いずれにせよ、優れたプロファイリングは問題解決に大いに役立つだろう。何がコストがかかるのかすぐにわかるようになるだろう。
ここでの問題の一部は社会的なものだ。言語設計者は高速なコンパイラを書くのが好きだ。それが彼らのスキルを測る方法なのだ。彼らはプロファイラをせいぜいアドオンだと考えている。しかし実際には、優れたプロファイラは、高速なコードを生成するコンパイラよりも、言語で書かれた実際のプログラムの速度を向上させるのに役立つかもしれない。ここでも、言語設計者はユーザーとの接点がやや薄い。彼らは少し間違った問題を非常にうまく解決しているのだ。
アクティブプロファイラを持つのは良いアイデアかもしれない。つまり、プログラマが要求するのを待つのではなく、パフォーマンスデータをプログラマにプッシュするのだ。例えば、プログラマがソースコードを編集するときに、エディタがボトルネックを赤で表示できる。もう一つのアプローチは、実行中のプログラムで何が起こっているかを何らかの形で表現することだろう。これは、多くの実行中のプログラムを監視できるサーバーベースのアプリケーションで特に大きな利点となるだろう。アクティブプロファイラは、プログラムの実行中にメモリ内で何が起こっているかをグラフィカルに表示したり、何が起こっているかを音で知らせたりすることもできる。
音は問題の合図として優れている。私が働いていたある場所では、ウェブサーバーで何が起こっているかを示す大きなダイヤル盤があった。針は小さなサーボモーターによって動かされ、それが回るとわずかな音を立てた。私は自分の机からその盤を見ることはできなかったが、音によって、サーバーに問題があることをすぐに知ることができた。
非効率なアルゴリズムを自動的に検出するプロファイラを書くことさえ可能かもしれない。特定のメモリアクセスのパターンが悪いアルゴリズムの確かな兆候であることが判明しても驚かないだろう。もしコンピュータの中に私たちのプログラムを実行する小さな男が走り回っているとしたら、彼は連邦政府の職員と同じくらい長く悲痛な仕事の話をするだろう。私はしばしば、プロセッサを多くの無駄な骨折りに送り込んでいると感じるが、それが何をしているのかをうまく見る方法がなかった。
現在、多くのLispがバイトコードにコンパイルされ、それがインタプリタによって実行される。これは通常、実装を移植しやすくするために行われるが、有用な言語機能となる可能性がある。バイトコードを言語の公式な一部とし、プログラマがボトルネックでインラインバイトコードを使用できるようにするのは良いアイデアかもしれない。そうすれば、そのような最適化もポータブルになるだろう。
エンドユーザーが知覚する速度の性質は変化しているかもしれない。サーバーベースのアプリケーションの台頭により、ますます多くのプログラムがI/Oバウンドになるかもしれない。I/Oを高速にすることは価値があるだろう。言語は、シンプルで高速なフォーマットされた出力関数のような直接的な対策だけでなく、キャッシュや永続オブジェクトのような深い構造的変更でも役立つ。
ユーザーは応答時間に興味がある。しかし、もう一つの種類の効率性がますます重要になるだろう。それは、プロセッサあたりでサポートできる同時ユーザー数だ。近い将来に書かれる興味深いアプリケーションの多くはサーバーベースになるだろうし、サーバーあたりのユーザー数は、そのようなアプリケーションをホストする者にとって重要な問題だ。サーバーベースのアプリケーションを提供するビジネスの設備投資費用において、これは除数となる。
長年、ほとんどのエンドユーザーアプリケーションでは効率性はあまり重要ではなかった。開発者は、各ユーザーがますます強力なプロセッサを机の上に持っていると仮定できた。そして、パーキンソンの法則により、ソフトウェアは利用可能なリソースを使うように拡大してきた。それはサーバーベースのアプリケーションで変わるだろう。その世界では、ハードウェアとソフトウェアが一緒に提供される。サーバーベースのアプリケーションを提供する企業にとって、サーバーあたりでサポートできるユーザー数が最終損益に非常に大きな違いをもたらすだろう。
一部のアプリケーションでは、プロセッサが制限要因となり、実行速度が最適化すべき最も重要なものとなるだろう。しかし、多くの場合、メモリが限界となる。同時ユーザー数は、各ユーザーのデータに必要なメモリ量によって決定されるだろう。ここでも言語は役立つ。スレッドの優れたサポートにより、すべてのユーザーが単一のヒープを共有できるようになるだろう。また、永続オブジェクトや、言語レベルでの遅延ロードのサポートも役立つかもしれない。
9 時間
人気のある言語に必要な最後の要素は時間だ。多くのプログラミング言語がそうであるように、いつか消えてなくなるかもしれない言語でプログラムを書きたいと思う人はいない。だから、ほとんどのハッカーは、言語が数年間存在していることを確認してからでなければ、それを使うことを検討しようとしないだろう。
素晴らしい新しいものを発明する人々は、この事実を発見してしばしば驚くが、人々にメッセージを伝えるには時間が必要だ。私の友人は、誰かに何かを頼まれても、最初のうちはめったに何もしない。彼は、人々が時々、結局欲しくないものだとわかるものを要求することがあるのを知っているのだ。時間を無駄にしないために、彼は3回目か4回目に頼まれるまで待つ。その頃には、頼んでいる人はかなりイライラしているかもしれないが、少なくとも彼らは本当に求めているものを欲しがっているだろう。
ほとんどの人は、新しいものについて聞くときに同様のフィルタリングを行うことを学んでいる。彼らは、何かについて10回聞くまで注意を払い始めない。彼らは完全に正当化される。話題の新しいものの大部分は時間の無駄であることが判明し、最終的には消えてなくなるからだ。VRMLの学習を遅らせたことで、私はそれを全く学ぶ必要がなかった。
だから、何か新しいものを発明する人は、人々にそれが理解され始めるまで何年もメッセージを繰り返し伝え続けることを覚悟しなければならない。私たちは、私が知る限り最初のウェブサーバーベースのアプリケーションを書いたが、それがダウンロードする必要がないことを人々に理解させるのに何年もかかった。彼らが愚かだったわけではない。彼らはただ私たちに耳を傾けていなかっただけなのだ。
良いニュースは、単純な繰り返しが問題を解決するということだ。あなたはただ自分の話を語り続けるだけでいい。そうすれば、最終的に人々は耳を傾け始めるだろう。人々が注意を払うのは、あなたがそこにいることに気づいた時ではなく、あなたがまだそこにいることに気づいた時なのだ。
勢いを得るのに通常時間がかかるのは、むしろ良いことだ。ほとんどの技術は、最初に発表された後もかなり進化する。特にプログラミング言語はそうだ。新しい技術にとって、少数のアーリーアダプターに数年間だけ使われることほど良いことはない。アーリーアダプターは洗練されていて要求が厳しく、あなたの技術に残っている欠陥を素早く洗い出す。ユーザーが少ないうちは、彼ら全員と密接に連絡を取ることができる。そして、アーリーアダプターは、システムを改善する際に、多少の破壊を引き起こしたとしても寛容だ。
新しい技術が導入される方法には2つある。有機的成長法とビッグバン法だ。有機的成長法は、典型的な、ぶっつけ本番で資金不足のガレージスタートアップに代表される。数人の男たちが、無名で活動しながら新しい技術を開発する。彼らはマーケティングなしでそれを発表し、最初は少数の(熱狂的に献身的な)ユーザーしかいない。彼らは技術を改善し続け、その間にユーザーベースは口コミで成長する。気づけば、彼らは大きくなっているのだ。
もう一つのアプローチであるビッグバン法は、VC(ベンチャーキャピタル)の支援を受け、大規模なマーケティングを行うスタートアップに代表される。彼らは製品開発を急ぎ、大々的な宣伝と共に発表し、すぐに(彼らが望むように)大規模なユーザーベースを獲得する。
一般的に、ガレージの連中はビッグバンの連中を羨む。ビッグバンの連中は洗練されていて自信に満ちており、VCから尊敬されている。彼らはあらゆる最高級のものを手に入れることができ、発表を取り巻くPRキャンペーンは彼らを有名人にするという副次的効果をもたらす。ガレージに座っている有機的成長の連中は、貧しく、愛されていないと感じる。しかし、私は彼らが自分を哀れむのは間違いであることが多いと思う。有機的成長は、ビッグバン法よりも優れた技術とより裕福な創業者を生み出すようだ。今日の支配的な技術を見てみれば、そのほとんどが有機的に成長したことがわかるだろう。
このパターンは企業にだけ当てはまるわけではない。スポンサー付き研究でも見られる。MulticsとCommon Lispはビッグバンプロジェクトであり、UnixとMacLispは有機的成長プロジェクトだった。
10 再設計
「最高の文章は書き直しである」とE. B. Whiteは書いた。すべての良い書き手はこれを知っており、それはソフトウェアにも当てはまる。設計の最も重要な部分は再設計だ。特にプログラミング言語は、十分に再設計されていない。
良いソフトウェアを書くためには、同時に2つの相反する考えを頭に入れておく必要がある。あなたは若いハッカーの自分の能力に対する素朴な信頼と、同時にベテランの懐疑心が必要だ。脳の半分でそんなに難しいことか?と考えながら、もう半分で決してうまくいかないと考えることができる必要がある。
秘訣は、ここに本当の矛盾はないと認識することだ。あなたは2つの異なることについて楽観的であり、懐疑的でありたいのだ。問題を解決できる可能性については楽観的である必要があるが、これまでに得られた解決策の価値については懐疑的である必要がある。
良い仕事をする人々は、自分が取り組んでいるものが良くないとしばしば考える。他の人々は彼らがしたことを見て驚嘆するが、創造者は心配でいっぱいだ。このパターンは偶然ではない。その心配が仕事を良くしたのだ。
希望と心配のバランスを保つことができれば、あなたの2本の足が自転車を前進させるのと同じように、プロジェクトを前進させるだろう。二段階イノベーションエンジンの第一段階では、問題を解決できるという自信に触発されて、猛烈に作業する。第二段階では、朝の冷徹な光の中で自分がしたことを見て、その欠陥を非常に明確に認識する。しかし、あなたの批判精神が希望を上回らない限り、あなたは確かに不完全なシステムを見て、「残りの道のりはどれほど難しいだろうか?」と考え、それによってサイクルを継続できるだろう。
2つの力をバランスさせるのは難しい。若いハッカーでは、楽観主義が優勢だ。彼らは何かを生み出し、それが素晴らしいと確信し、決して改善しない。年老いたハッカーでは、懐疑主義が優勢であり、野心的なプロジェクトに着手しようとさえしない。
再設計サイクルを継続させるためにできることは何でも良い。散文は、満足するまで何度も書き直すことができる。しかし、ソフトウェアは原則として、十分に再設計されない。散文には読者がいるが、ソフトウェアには_ユーザー_がいる。もし書き手がエッセイを書き直しても、古いバージョンを読んだ人々が、新しく導入された非互換性によって彼らの思考が壊されたと文句を言うことはまずないだろう。
ユーザーは諸刃の剣だ。彼らはあなたの言語を改善するのに役立つが、改善を妨げることもできる。だから、ユーザーを慎重に選び、その数をゆっくり増やすべきだ。ユーザーを持つことは最適化のようなものだ。賢明な道はそれを遅らせることだ。また、一般的に、あなたはいつでも思っている以上に多くの変更を行うことができる。変更を導入することは、絆創膏を剥がすようなものだ。痛みは感じた途端にほとんど記憶になる。
誰もが、委員会によって設計された言語を持つのは良いアイデアではないことを知っている。委員会は悪い設計を生み出す。しかし、委員会の最悪の危険は、再設計を妨げることだと私は思う。変更を導入するのは非常に手間がかかるため、誰も手間をかけたくないのだ。委員会が決定したことは、たとえほとんどのメンバーが気に入らなくても、そのままである傾向がある。
2人委員会でさえ再設計の邪魔になる。これは特に、2人の異なる人物によって書かれたソフトウェアの各部分間のインターフェースで起こる。インターフェースを変更するには、両者が同時に変更することに同意しなければならない。そのため、インターフェースは全く変更されない傾向があり、これは問題だ。なぜなら、それらはどんなシステムでも最も場当たり的な部分の一つである傾向があるからだ。
ここでの一つの解決策は、インターフェースが垂直ではなく水平になるようにシステムを設計することだろう。つまり、モジュールが常に垂直に積み重ねられた抽象化の層になるようにするのだ。そうすれば、インターフェースはどちらか一方によって所有される傾向がある。2つのレベルのうち下位のレベルは、上位のレベルが書かれている言語であるか、その場合下位レベルがインターフェースを所有するか、あるいは従属するものであり、その場合インターフェースは上位レベルによって決定される。
11 Lisp
これらすべてが示唆するのは、新しいLispに希望があるということだ。Lispを含め、ハッカーが望むものを提供するどんな言語にも希望がある。私たちは、ハッカーがLispの奇妙さにうんざりしていると考えていたのは間違いだったかもしれないと思う。この心地よい幻想は、Lisp、あるいは少なくともCommon Lispの本当の問題、つまりハッカーがやりたいことをやるにはひどいという問題を見えなくしていたのかもしれない。ハッカー向け言語には強力なライブラリとハックする何かが必要だ。Common Lispにはどちらもない。ハッカー向け言語は簡潔でハック可能だ。Common Lispはそうではない。
良いニュースは、ひどいのはLispではなく、Common Lispだということだ。もし私たちが真のハッカー向け言語である新しいLispを開発できれば、ハッカーはそれを使うだろうと私は思う。彼らは仕事をこなすどんな言語でも使うだろう。私たちがしなければならないのは、この新しいLispが他の言語よりも重要な仕事をより良くこなすことを確実にすることだけだ。
歴史はいくつかの励みになる点を提供している。時が経つにつれて、次々と登場する新しいプログラミング言語は、Lispからますます多くの機能を取り入れてきた。あなたが作った言語がLispになる前にコピーすべきものは、もはやほとんど残っていない。最新の話題の言語であるPythonは、中置構文でマクロがない、薄められたLispだ。新しいLispは、この進歩における自然な一歩となるだろう。
私は時々、それをPythonの改良版と呼ぶのが良いマーケティングの仕掛けになるだろうと考える。Lispよりもクールに聞こえるからだ。多くの人々にとって、Lispは括弧だらけの遅いAI言語だ。Fritz Kunzeの公式伝記は、Lワードに言及することを慎重に避けている。しかし、私の推測では、新しいLispをLispと呼ぶことを恐れるべきではない。Lispは、最高のハッカーたち、例えば6.001を受講してそれを理解した人々の中には、まだ多くの潜在的な尊敬がある。そして、彼らこそあなたが獲得する必要のあるユーザーなのだ。
「『ハッカーになる方法』」の中で、Eric RaymondはLispをラテン語やギリシャ語のようなもの、つまり実際に使うことはなくても知的訓練として学ぶべき言語だと説明している。
Lispは、最終的にそれを理解したときに得られる深い悟りの経験のために学ぶ価値がある。その経験は、たとえLisp自体をあまり使わなくても、残りの人生でより良いプログラマにするだろう。
もし私がLispを知らなかったら、これを読んで疑問を抱かせるだろう。「より良いプログラマにする言語」がもし何か意味を持つとすれば、それはプログラミングにより適している言語を意味する。そして、それは実際、Ericが言っていることの含意なのだ。
そのアイデアがまだ漂っている限り、たとえLispと呼ばれても、ハッカーは新しいLispを十分に受け入れるだろうと私は思う。しかし、このLispは、1970年代の古典的なLispのように、ハッカー向け言語でなければならない。それは簡潔で、シンプルで、ハック可能でなければならない。そして、ハッカーが今やりたいことをするための強力なライブラリを持っていなければならない。
ライブラリに関しては、PerlやPythonのような言語を彼らの得意分野で打ち負かす余地があると思う。今後数年間で書かれる必要がある新しいアプリケーションの多くは、サーバーベースのアプリケーションになるだろう。新しいLispがPerlと同じくらい優れた文字列ライブラリを持たない理由はないし、もしこの新しいLispがサーバーベースのアプリケーションのための強力なライブラリも持っていれば、非常に人気が出る可能性がある。本物のハッカーは、いくつかのライブラリ呼び出しで難しい問題を解決できる新しいツールを鼻であしらったりはしないだろう。覚えておいてほしい、ハッカーは怠惰なのだ。
サーバーベースのアプリケーションのためのコア言語レベルのサポートがあれば、さらに大きな利点となるだろう。例えば、複数ユーザーを持つプログラムに対する明示的なサポートや、型タグレベルでのデータ所有権などだ。
サーバーベースのアプリケーションは、この新しいLispが何をハックするために使われるかという質問への答えも与えてくれる。Unixのスクリプト言語としてLispを改善しても損はないだろう。(これ以上悪くするのは難しいだろうが。)しかし、既存の言語を打ち負かすのがより簡単な分野があると思う。Tclのモデルに従い、Lispをサーバーベースのアプリケーションをサポートするための完全なシステムと共に提供する方が良いかもしれない。Lispはサーバーベースのアプリケーションに自然に適合する。UIが単なる一連のウェブページである場合でも、レキシカルクロージャはサブルーチンの効果を得る方法を提供する。S式はHTMLにうまくマッピングされ、マクロはそれを生成するのに優れている。サーバーベースのアプリケーションを書くためのより良いツールが必要であり、新しいLispも必要であり、この2つは非常によく連携するだろう。
12 夢の言語
要約として、ハッカーの夢の言語を記述してみよう。夢の言語は美しい、クリーンで、簡潔だ。高速に起動する対話型トップレベルを持つ。ごくわずかなコードで一般的な問題を解決するプログラムを書くことができる。あなたが書くどんなプログラムのコードも、ほとんどすべてがあなたのアプリケーションに特有のコードだ。他のすべてはあなたのために行われている。
言語の構文は極度に簡潔だ。不要な文字を入力する必要はなく、シフトキーを多用する必要もない。
大きな抽象化を使って、プログラムの最初のバージョンを非常に素早く書くことができる。後で最適化したいときには、どこに注意を集中すべきかを教えてくれる本当に優れたプロファイラがある。内部ループを驚くほど高速にすることができ、必要であればインラインバイトコードを書くことさえできる。
学ぶべき良い例がたくさんあり、言語は十分に直感的であるため、数分で例から使い方を学ぶことができる。マニュアルをあまり見る必要はない。マニュアルは薄く、警告や但し書きが少ない。
言語は小さなコアを持ち、コア言語と同じくらい注意深く設計された、強力で高度に直交するライブラリを持つ。ライブラリはすべてうまく連携し、言語内のすべてが高級カメラの部品のようにぴったりと収まる。何も非推奨にされたり、互換性のために残されたりしていない。すべてのライブラリのソースコードはすぐに利用可能だ。オペレーティングシステムや他の言語で書かれたアプリケーションと対話するのは簡単だ。
言語は層状に構築されている。高レベルの抽象化は、下位レベルの抽象化から非常に透過的な方法で構築されており、必要であればそれを手に入れることができる。
絶対に隠されなければならないもの以外は、何もあなたから隠されていない。言語は、何をすべきかを指示する方法としてではなく、作業を省く方法としてのみ抽象化を提供する。実際、言語はあなたがその設計における対等な参加者であることを奨励する。構文を含め、そのすべてを変更することができ、あなたが書くものは何でも、可能な限り、事前に定義されたものと同じステータスを持つ。
注釈
[1] 現代のアイデアに非常に近いマクロは、Lisp 1.5がリリースされた2年後の1964年にTimothy Hartによって提案された。当初欠けていたのは、変数キャプチャと多重評価を避ける方法だった。Hartの例は両方の影響を受ける。
[2] _脳に空気が触れるとき_の中で、脳神経外科医のFrank Vertosickは、彼のチーフレジデントであるGaryが外科医と内科医(「ノミ」)の違いについて話す会話を語っている。
Garyと私は大きなピザを注文し、空いているブースを見つけた。チーフはタバコに火をつけた。「あの忌々しいノミどもを見ろ、一生に一度しか見ないような病気についてべらべら喋っている。それがノミどもの問題なんだ、彼らは奇妙なものしか好きじゃない。日常の症例は嫌いなんだ。それが俺たちとあのクソみたいなノミどもとの違いだ。ほら、俺たちは大きくジューシーな腰椎椎間板ヘルニアが大好きだが、彼らは高血圧が嫌いなんだ…。」
腰椎椎間板ヘルニアをジューシーだと考えるのは難しい(文字通りでない限り)。しかし、彼らが何を意味するのかはわかる気がする。私はしばしば、ジューシーなバグを追跡しなければならなかった。プログラマでない人には、バグに喜びを感じるなど想像しにくいだろう。すべてがただ動く方が良いに決まっている。ある意味ではそうだ。しかし、ある種のバグを追い詰めることには、紛れもなく陰鬱な満足感があるのだ。