Chapter 14. Languages

To C or Not To C?

『ハムレット』のパロデー。

Unix's Cornucopia of Languages

Cornucopia を辞書で引くと «a symbol of plenty consisting of a goat's horn overflowing with flowers, fruit, and corn» (OED) とある。豊穣の象徴?

Unix は計算機の歴史における他のどの OS よりも多くの異なる言語の寄主である可能性がある。その多様性の理由は二つはある:

  • Unix が研究や教育の基礎として広く使われている。
  • アプリケーションの設計と適切な実装言語を釣り合わすことで、生産性が大きく変わる という事実。

Unix の伝統は応用領域固有言語や、現在一般的にスクリプト言語と呼ばれているものの設計を奨励している。

スクリプト言語という術語は少々扱いにくい。そう呼ばれている言語はその呼び名の枠を超えた能力を持つまでに成長しており、独立した汎用プログラミング言語になっている。

これらすべてを「スクリプト言語」で一緒くたにできる理由の一つは、これらの言語がほとんど同じ発達をしているからだ:

  • インタープリターを持つことで、動的ストレージ管理の自動化も比較的容易になる。
  • 動的なストレージ管理を自動化するには、値のコピーや生のポインターを渡すのではな く、参照を使う必要がある。
  • 参照を使うことで、実行時多態性とオブジェクト指向は次の段階に簡単に進むことがで きる。

Unix 哲学を効果的に応用するにはプログラマー個人の言語操作能力の集合に C 以上のものが含まれている必要がある。

アプリケーション言語の選択は典型的な信仰の問題だ。

People get very attached to these tools and will sometimes defend them past all reason.

Why Not C?

C 言語は Unix の第一言語だ。

1980 年代初頭から C 言語は計算機業界のほとんどの場所でシステムプログラミングを支配するようになった。C とその子孫である C++ は本書執筆時 2003 年時点でアプリケーションプログラミングをほぼ完全に支配している。例外は:

  • 科学技術計算における Fortran
  • 銀行や保険会社における COBOL 金融アプリケーション

C/C++ は新しいアプリケーションの開発を始めるのに、今日ではほとんど常に誤った手段であると著者は断言する。

C/C++ は実装とデバッグにかかる時間の増加を犠牲にして効率を最適化している。システムプログラムや時間的に重要なアプリケーションのカーネルを書くことは今でも理にかなっているが、演算装置は千倍速くなり、記憶容量は千倍大きくなり、記憶装置は万倍大きくなっている。

こうしたコストの急落は、プログラミングの経済性を根本的に変えてしまう。たいていの状況では C 言語が許す限りマシンの資源を節約しようとしても、もはや意味がない。

代わりに、経済的に最適な選択とは次だ:

  • デバッグ時間を最小化し、
  • 人間によるコードの長期的な保守性を最大化する

したがって、ほとんどの種類の実装(試作を含む)は新世代インタプリター型言語やスクリプト言語の方が適している。

C/C++ の中心的な問題はプログラマーに独自のメモリー管理を要求することにある:

  • 変数の宣言
  • ポインター連鎖リストの明示的な管理
  • バッファーの拡張
  • バッファーオーバーランの検出と防止
  • 動的ストレージの割り当てと解放

この仕事の一部はガベージコレクターを C 言語に後付けすることで自動化することができる。しかし C 言語の設計上、これが完全な解決策になることはあり得ない。

メモリー管理は複雑化とエラーの莫大な原因だ。

[124]。バッファ・オーバーランは、クラッシュやセキュリティ・ホールの一般的な原因である。 動的メモリ管理は、メモリ・リークやステール・ポインタの問題のような、陰湿で追跡が困難なバグを生み出すことで特に悪名高い。

  • 複雑なデータ構造を操作するプログラムでは、開発時間の三、四割がストレージ管理に 費やされていると推定する研究 (Hans Boehm. Advantages and Disadvantages of Conservative Garbage Collection) がある。
  • (確かな数字があるわけではないが)経験豊富なプログラマーの多くは、メモリー管理 のバグが実世界のコードにおける永続的なエラーの唯一最大の原因であると考えている。

今日の状況下では、メモリー管理を自動化する実装言語(少し多めのサイクルとコアを使用する代償としてバグが一桁減る)の方がはるかに理にかなっている。

実世界のプログラムは演算装置そのものの使用効率よりも、I/O イベントの待ち時間、ネットワークの待ち時間、キャッシュラインのフィルによって制限される傾向がある。

Unix 界では特に 1990 年前後からこのような考え方に徐々に近づいている。多くの Unix プログラマーは Perl や Python が教えてきたことをまだ吸収している。

Unix 界以外でも同じ傾向がよりゆっくりと起きている。例えば:

  • Microsoft Windows や NT のアプリケーション開発で見られる C++ から Visual Basic への継続的な移り変わり
  • メインフレームの世界における Java への移行

C/C++ に対する反論は他の(メモリー管理をプログラマーに任せるという基本的な設計の)従来型コンパイル言語にも同じように当てはまる。従来の言語間の違いは表面的なものにとどまる。

Interpreted Languages and Mixed Strategies

手作業によるメモリー管理を回避する言語では、実行ファイルのどこかにメモリーマネジャーを内蔵している。このような言語の実行時動作環境はプログラム部分(スクリプトそのもの)とインタープリター部分に分かれており、インタープリターが動的ストレージを管理している。

Unix を含む最新の OS では、インタープリターの核心を複数のプログラム部分で共有し、それぞれの実際の間接費を減らすことが可能だ。

1970 年代半ば、Unix シェルは完全なインタプリター型プログラミング言語として設計されていた。その当時でも、シェルだけでプログラムを書いたり、定型の実用品や C 言語の自作プログラムをつなぎ合わせて、部分の総和以上のものを作るための接着ロジックを書くためにシェルを使うことはよくあった。

Advanced shell programming mixes languages freely, employing both binaries and interpreted elements from half a dozen or more other languages for subtasks.

上の記述の要点はバイナリーとスクリプトの分量に言及していることだと思う。

それぞれの言語が得意とすることを行い、各部品は他のものと狭いインターフェイスを持つモジュールであり、汎用言語で単一の怪物一枚岩としてコードされた場合よりも全体の大域的複雑度がはるかに低くなる。

Language Evaluations

言語を混在させることはプログラミングの知識集約型様式だ。これをうまくやるには次の両方が必要となる:

  • 適切な種類の言語に関する実用的な知識
  • それらの言語の得意分野や組み合わせ方に関する専門知識

C

C 言語に適しているプログラムの性質:

  • 最高速度が要求される
  • 同時性が要求される
  • OS カーネルと緊密に結合している

小さなアプリケーションの残りの部分を C で書くことが正当化されるほど効力が大きい場合もある。

現代の条件下では C を高水準アセンブラーと考えるのがおそらく最善だろう。C の標準規格は、標準 I/O ライブラリーなど、Unix 仮想機の機能の多くを他の OS に輸出してきた。OS を持たないものに可能な限り近づけたいが、ポータブルであり続けたい場合に C 言語が使われる。

C 言語を学ぶべき理由のひとつは、ハードウェアアーキテクチャー水準での考え方を学ぶのに役立つからだ。すでにプログラマーである人々にとって、C 言語の最高の参考書でありチュートリアルであるのは、やはり The C Programming Language だ。

Unix の亜種間での C コードの移植はほとんどの場合可能であり、たいていは簡単だが、特定の亜種(シグナルやプロセス制御など)を正しく移植するのは難しい (Chapter 17)。

高品質 C コンパイラーがインターネット上のオープンソースソフトウェアとして入手できる。

the best-known and most widely used is the Free Software Foundation's GNU C compiler (part of GCC, the GNU Compiler Collection), which has become the native C of all open-source Unix systems and many even in the closed-source world.

移植版は Windows でさえ利用可能だ。FSF のサイト で入手可能だ。

C の長所は資源効率と機械との距離の近さ。短所はプログラミングが資源管理地獄であることだ。

C Case Study: fetchmail

C 言語の最良の事例研究は Unix カーネルそのものだ。ハードウェアの水準の操作を自然に支援する言語は強みとなる。

C の構造体機能と同等のものはその代替言語のほとんどに存在しない。注目に値する例外は Python と Java だ。

次のパラグラフの記述が気になる:

Finally, fetchmail requires the ability to parse a fairly complex specification syntax for per-mail-server control information. In the Unix world this sort of thing is classically handled by using C code generators that grind out source code for a tokenizer and grammar parser from declarative specifications. The existence of yacc and lex was a point in favor of C.

宣言的仕様をすり潰すことで C で書かれた字句解析コードおよび文法解析コードを生成する過程があることになる。

fetchmail might reasonably have been coded in Python, albeit with possibly significant loss of performance.

当時の Python はべらぼうに遅いから、こういう見解になる。

fetchmail が C 言語プログラムである本当の理由は、すでにそれで書かれた祖先から徐々に変異して進化してきたからだ。

本書の以前にも触れているし、この後にも触れるが、関連ツール fetchmailconf は C ではなく Python で書いた。

C++

C++ は C との後方互換性を要求されたため、設計に多くの妥協を余儀なくされた。とりわけ、この要求のために、C++ は動的メモリー管理を完全自動化することができず、C の最も深刻な問題に対処することができなかった。

C++ は過度に装飾的かつ複雑なものになった。

今日(2003年)、オープンソースのアーカイブを調査してみると、C++ の使用は次のオブジェクト指向が上手くいく分野に集中していて、他の分野ではほとんど見られない:

  • GUI
  • マルチメディアツールキット
  • ゲーム

C++ プログラムの寿命費用は C, FORTRAN, Ada の同等品よりも高いという証拠がいくつかある。

C++ はオブジェクト指向以外の重要なアイデアをいくつか取り入れている:

  • 例外処理
  • STL を含むテンプレート

C++ はあらゆる人にあらゆることを可能にしようと試みているが、その代償として、個々のプログラマーの頭脳は処理し切れないほどの複雑さを抱える。C++ の主要設計者は一人のプログラマーがすべてを把握できるとは思っていないと認めている (Chapter 4)。

多くの種類のアプリケーションにとって、オブジェクト指向機能は重要ではなく、C 言語に複雑さを加えるだけで、大した利点はない。

次の著者の見解は私の経験とかなり異なる:

if C++ were unequivocally superior to C it would now dominate.

まとめ:

  • 優れた点
    • コンパイルによる効率性
    • オブジェクト指向や汎用プログラミングのための機能を兼ね備えている
  • 悪い点
    • 過度に装飾的で複雑である
    • 複雑過ぎる設計を助長する傾向がある

古典的な C++ の参考書は Stroustrup の The C++ Programming Language だ。なお、第四版が最新と思われる。

あと二冊紹介しているが、C++ 本の事情なら会社員時代の私のほうが詳しい。

GNU コンパイラーコレクションは C++ コンパイラーを含む。

C++ Case Study: The Qt Toolkit

Qt は Motif, MacOS Platinum, Microsoft Windows インターフェイスの見てくれや操作感を模倣するように意図的に(そして上手く)設計された、GUI を書くための API だ。また、XML, ファイルアクセス、ソケット、スレッド、タイマー、時間日付処理、データベースアクセス、抽象データ型各種、Unicode 用のクラスが用意されている。

KDE プロジェクトの重要かつすぐに使える部品であり、競争力のある GUI とデスクトップ生産性ツールの統合集合を生み出すオープンソース世界の二つの取り組みの先人だ。

C++ 実装は UI 部品をカプセル化するためのオブジェクト指向言語の長所を示している。オブジェクトを支援する言語では UI 要素の視覚的な階層をクラス階層によってコード上できれいに表現することができる。

Comparison with the notoriously baroque C API of Motif is instructive.

これは気になる。

Note

クラス階層の美しさは https://doc.qt.io/qt-6/classes.html の索引をザッと 見るだけでも窺い知れる。本文の趣旨に従って Qt Widgets から見るといい。

Shell

Version 7 Unix の Bourne Shell, sh は Unix 初の持ち運び可能インタープリター型言語だ。

現在では sh は上位互換性のある KornShell, ksh の亜種に取って代わられており、その中で最も重要なのは Bourne Again Shell, bash だ。

他にもシェルがいくつか存在し、対話的に使用されている。しかしプログラミング言語としては重要ではない。最もよく知られているのは、おそらく C Shell, csh であり、スクリプトを書くには適していないことで悪名高い。

単純なシェルプログラムは極端に簡単かつ自然に書ける。

The Unix tradition of rapid prototyping in interpretive languages began with shell.

シェル構文の一部がたいへん混乱しやすいという欠点は、対話的コマンドラインインタープリターとしてのシェルの有用性を維持するために、シェルの設計におけるプログラミング言語部分の妥協に関係する。

プログラムは、sort(1) などの他言語プログラム、sed(1), awk(1) のような標準的な小規模言語を多用している場合でも、シェルで書かれる。しかし、この種のプログラムは現在では Perl や Python で書かれており、シェルは最も単純な種類のラッパーやシステム起動時の初期化スクリプトのために維持されている。

このような基本的なシェルプログラミングは Unix の入門書であれば十分にカバーされているはずだ。The Unix Programming Environment (Brian W. Kernighan, Rob Pike) は中級および上級シェルプログラミングに関する最良の教科書の一つだ。

複雑なシェルスクリプトは移植性に問題があることが多いが、それはシェルそのものが原因ではなく、部品として利用可能な他のプログラムを想定しているからだ。

まとめ:シェルの長所は、小さなスクリプトであれば非常に自然で素早く実行できることです。 シェルの悪い面は、大規模なシェルスクリプトは、必ずしも同じ動作をするわけでもなく、すべてのターゲットマシンに存在するわけでもない多くの補助コマンドに依存することです。 また、大規模なシェルスクリプトの依存関係を分析するのも容易ではない。

Unix システムやエミュレーターにはすべてシェルが搭載されている。シェルをビルドしたりインストールしたりする必要はほとんどない。Linux や他の最先端の Unix の標準シェルは現在 bash(1) だ。

Case Study: xmlto

DocBook ならよく書いていたから話は理解できる。

xmlto is a driver script that calls all the commands needed to render an XML-DocBook document as HTML, PostScript, plain text, or in any one of several other formats (we'll take a closer look at DocBook in Chapter 18). It is written in bash.

適切なスタイルシートで XSLT エンジンを呼び出し、その結果を後処理器に渡すという詳細を処理する。

  • HTML/XHTML の場合、XSLT 変換が作業のすべてを行う。
  • プレーンテキストの場合も XML は HTML に加工されるが、その後処理で lynx(1) の -dump モードに渡り、フラットテキストに加工される。
  • PostScript の場合、XML は FO に変換され、後処理において TeX マクロに変換され、 tex(1) によって DVI 形式に変換され、最後に dvi2ps(1) を使う。

xmlto は単一のフロントエンドのシェルスクリプトで構成される。スクリプトプラグインのいずれかを呼び出す。各プラグインもシェルスクリプトだ。

この建築方式は指定された出力形式に関する情報のすべてが一箇所(対応するスクリプトプラグイン)に存在することを意味し、新しい出力形式を追加してもフロントエンドのコードにまったく影響を与えない。

xmlto は中規模のシェルアプリケーションの良い例だ。

  • C/C++ はスクリプトを書くには厄介で、意味をなさない。
  • 内部データ構造や複雑なロジックを持たない、単純命令の発令なのでシェル十分だ。
  • シェルには、対象とするシステムでどこにでもあるという大きな利点がある。

Case Study: Sorcery Linux

Sorcerer GNU/Linux is a Linux distribution that you install as a small, bootable foothold system just powerful enough to run bash(1) and a couple of download utilities. With this code in place, you can invoke Sorcery, the Sorcerer package system.

Linux の一種であるものと、パッケージシステムであるものがある。

Sorcery システムはすべてシェルで書かれている。プログラムのインストール手順はシェルが適している小規模で単純なプログラムになる傾向がある。この独特なアプリケーションでは Sorcery 作者が必要な補助プログラムが足場システムに存在することを保証できるため、シェルの主な欠点は消える。

Note

これは少し調べただけで詳細がわからなかった。

Perl

Perl は強化シェルだ。awk(1) を置き換えるために特別に設計され、混合言語スクリプトプログラミングの接着剤としてシェルを置き換えるために拡張された。

Perl の長所は:

  • テキスト、行指向のデータ形式をパターン指向で処理するための強力な内蔵機能。
  • シェルよりもはるかに強力なデータ構造。要素型が混在する動的配列や、名前と値のペ アを便利かつ高速に検索できるハッシュ型などがある。
  • Unix API 全体の内部バインディング。C 言語の必要性を劇的になくした。
  • 大規模で活発なオープンソース共同体が育ってきた。

Note

バインディングは二つのプログラミング言語間の橋渡しをするラッパーライブラリーだ。 ある言語用に書かれたライブラリーを別の言語でも使えるようにする。

Perl の短所:

  • 関数の引数渡しの規約など、言語仕様の一部が救いようのないほど醜く複雑だ。
  • 使い始めるのはシェルよりも難しい。
  • 小さなプログラムは強力だが、モジュール性を維持し、プログラムの規模が大きくなる につれて設計を統率し続けるには慎重な規律が必要となる。
  • 歴史の初期に決定されたいくつかの制限的な設計を元に戻すことができなかったため、 より高度な機能の多くに壊れやすい感触がある。

Perl に関する参考書の決定版は Programming Perl だ。ただし整理整頓が悪い。より入門的で叙述的な扱いは、Learning Perl にある。

Perl は Unix システム上で普遍だ。同じメジャーリリースレベルの Perl スクリプトは(拡張モジュールを使用しない限り)Unix 間で容易に移植できる傾向がある。Perl の実装は Windows や MacOS でも利用可能である(かつ十分に文書化されている)。Perl/Tk はプラットフォーム横断的に GUI 機能が使用可能だ。

Perl の最も優れた面は、正規表現を多用する小さなスクリプトのためのパワーツールであることだ。Perl の悪い面は、醜く、とげとげしく、大量に保守できないことだ。

A Small Perl Case Study: blq

スクリプト blq はスパムを照会する。

小さな Perl スクリプトの良い例であり、この言語の長所と短所の両方を示している。

  • 正規表現マッチングを多用している。
  • 拡張モジュール Net::DNS は標準モジュールではないゆえ、条件付きでインクルード しなければならない。

Perl コードとしては blq は例外的にきれいで規律正しい。それでも、Perl 慣用コードに慣れていなければ一部は読めない。例:

$0 =~ s!.*/!!;

Tcl と Python はどちらもこの種の小さなスクリプトには適しているが、どちらも blq が多用する正規表現マッチングのための Perl の便利な機能がない。Emacs Lisp の実装は Perl のものよりもさらに速く、コンパクトに書けるだろう。

A Large Perl Case Study: keeper

Tcl

  • Tcl: Tool Command Language
  • 1990 年。
  • コンパイルされた C ライブラリーとリンクするように設計された小規模言語インタプ リター。
  • C プログラム内から呼び出され、それらに値を返すスクリプトにも適している。

Tcl の上に構築されたもので、Tcl 共同体以外でも広く使われているものがいくつかある。最も重要なものは二つだ:

Tk
ボタン、ダイアログボックス、メニューツリー、スクロールテキストウィジェットを 簡単に素早く作成し、入力を収集できる、より優しく親切な X インターフェイス。
Expect
応答が大きく変化する完全な対話型プログラムを比較的簡単にスクリプト化できる言語。

Tk がきわめて重要なので、この言語はしばしば Tcl/Tk と呼ばれる。Tk は Perl や Python でもよく使われる。

Tcl の主な利点は柔軟で根本的に単純であることだ。構文はたいへん奇妙だが完全に一貫している。予約語はなく、関数呼び出しと内蔵構文との間に構文上の区別はない。したがって、Tcl 言語インタプリター自体は、Tcl の内部から効果的に再定義することができる。これが Expect のようなプロジェクトを合理的にしている。

Tcl の主な欠点は

  • 純粋な言語には名前空間制御とモジュール化のための弱い機能しかないことで、そのう ちの upvaruplevel は細心の注意を払って使わないとかなり危険だ。
  • 連想リスト以外のデータ構造もない。そのため Tcl の拡張性は低く、適度な行数(数 百行以上)の純粋な Tcl プログラムを整理し、デバッグするのは難しい。
  • 文字列の引用符と中括弧の区別は頭痛になるだろうし、引用符や中括弧が必要な場合の 規則も少し厄介だ。

純粋な Tcl は Unix API の比較的小さくてよく使われる部分(ファイル操作、プロセス生成、ソケット)へのアクセスしか与えない。Tcl 拡張はより豊富な機能を備えるが、どこにでもインストールされる保証はない。

Tcl and the Tk Toolkit
Tcl の原典。
Practical Programming in Tcl and Tk
上の本を取って代わった。
Experience with Tcl/Tk for Scientific and Engineering Visualization
ラピッドプロトタイピングとプロダクションツールとしての Tcl の長所と短所を要約 した、実世界の Tcl プロジェクトの説明

Tcl スクリプトにはシェルスクリプトと同様の移植性の問題がある。言語自体は移植性が高いが、呼び出すコンポーネントは移植性が低い場合がある。言語自体の移植性は高いが、呼び出すコンポーネントの移植性は低いかもしれない。

Tcl の実装は Windows, MacOS, その他多くのプラットフォームに存在する。Tcl/Tk スクリプトは GUI 機能を持つあらゆるプラットフォームで動作する。

  • 優れた点
    • 余裕のあるコンパクトな設計
    • インタプリターの拡張性
  • 悪い点
    • 奇妙な位置構文解析
    • データ構造と名前空間制御の弱さ

Case Study: TkMan

TkMan は Unix の man ページと Texinfo 文書の閲覧ソフトだ。Tk を用いた、純正の man(1) や xman(1) が支援するものよりもかなり洗練された GUI だ。

TkMan は Tcl のあらゆる技法をほぼ全面的に披露しているので良い事例研究になる。ハイライトは:

  • Tk との一体化
  • 他の Unix アプリケーションをスクリプトで制御(検索エンジンなど)
  • Texinfo マークアップを解析するため Tcl を使用

他の言語のどれを使っても、このコードの大部分を構成する Tk GUIへの直接的なインターフェイスにはならなかっただろう。

Moodss: A Large Tcl Case Study

Moodss はシステム管理者向けのグラフィカルな監視アプリケーションだ。MySQL, Linux, SNMP ネットワーク、Apache のログを監視し、統計情報を収集することができ、ダッシュボードと呼ばれる表計算シートのような GUI 盤を通して、それらをダイジェストで表示することが可能だ。

  • 監視モジュールは Tcl だけでなく、Python や Perl でも書くことができる。
  • コードは洗練され、Tcl 共同体では模範とみなされている。
  • プロジェクトのウェブサイトがある。

Moodss のコアは 約 18,000 行の Tcl で構成されている。自作オブジェクトシステムを含む Tcl 拡張を使用している。

Python

Note

本書出版から精読時点までの Python の成長が著しいため、記述の一部はさすがに古 びてしまっている。

  • 1991 年登場。
  • C 言語と密接に統合するために設計されたスクリプト言語であり、C の DLL とデータ を動的にアクセスすることが可能。
  • C 言語から組み込みスクリプト言語として呼び出すことが可能。
  • 設計が綺麗かつ上品。
  • モジュール機能が優れている。
  • コードをオブジェクト指向の流儀で書くことも、古典的な手続き型 C 言語のような方 法で書くことも可能。
  • Perl が真似たとも言われるほどの型システムを有している。コンテナーなど。
  • Lisp ハッカーがよろこぶ無名ラムダがある。
  • Tk が同梱されていて、GUI を簡単に構築することができる。

Python には重要なインターネットプロトコルのほとんど (SMTP, FTP, POP3, IMAP, HTTP) のクライアントクラスを標準モジュールに含む。そのため、プロトコルロボットやネットワーク管理用配管の構築に適している。

ここで説明するインタプリター型言語の中で、Python と Java は大規模で複雑なプロジェクトに scale up するのに最も適している。Python は多くの点で Java よりも単純であり、rapid prototyping への親和性は場合によっては Java よりも優位に立つかもしれない。

Python は生の実行速度では C/C++ に太刀打ちできない。しかし、Python は C 言語と組み合わせるのが簡単なので、性能が重要な Python モジュールは C 言語に翻訳して、速度を大幅に向上させるとよい。

事実、Python は主要なスクリプト言語の中で最も効率が悪く遅いと一般に考えられている。これは実行時の型多態性の代償だ。しかし、このような理由で Python を拒絶するのは待て。アプリケーションのほとんどは Python がもたらす以上の性能を必要としないし、そのように見えるものでさえ、一般的には、Python のインタプリターの間接費の影響を完全に打ち消すような、ネットワークやディスクの待ち時間のような外部の待ち時間によって制限されている。

Python は小規模なプロジェクトや正規表現機能に大きく依存する接着剤スクリプトでは Perl に表現力で負ける。極小プロジェクトに対しては行き過ぎだ。シェルや Tcl の方が適していることがある。

Perl 同様、Python には確立された開発共同体があり、https://www.python.org/ には多くの有用な実装、道具、拡張モジュールが見られる。

Note

現代なら PyPI などか?

Python の拡張に関する広範なオンラインドキュメントも上記 Web サイトにある。

  • Python のプログラムは Unix 間や他の OS 間でもかなり移植性が高い傾向がある。標 準ライブラリーは十分に強力で、移植性のない補助プログラムの使用を大幅に削減でき る。
  • Python の実装は Windows と MacOS で利用可能。
  • プラットフォーム横断的 GUI 開発は Tk または他のツールキットで可能。

まとめ:

  • 優れた点:きれいで読みやすいコードを奨励し、使いやすさと大規模プロジェクトへの 拡張性を両立させていることだ。
  • 悪い点:非効率で遅い。コンパイル言語と比べてだけでなく、他のスクリプト言語と比 べてもだ。

Note

二十年以上経った現代では Python の効率はだいぶマシになったと考えられる。

A Small Python Case Study: imgsizer

Note

なぜか本書著者の Web サイトに本ツールのヘルプがある: http://www.catb.org/~esr/imgsizer/imgsizer.html

もともと Perlで書かれたもので、Perl が得意とするパターン駆動型の小さなテキスト処理ツールのほぼ理想的な例だった。後に Python に翻訳され、標準モジュールによる HTTP 支援を利用するようになった。

動的な文字列処理と洗練された正規表現マッチングが必要なため、

  • C/C++ で書いたならばはかなり骨が折れただろう。ずっと大きく、読みにくいものに なっただろう。
  • Java ならばメモリー管理の問題は解決できただろうが、テキストのパターンマッチン グでは C/C++ より表現力が高いとは言い難い。

A Medium-Sized Python Case Study: fetchmailconf

Chapter 11 では fetchmail/fetchmailconf を調べた。Python の強みは fetchmailconf がよく示している。

fetchmailconf は Tk 使ってマルチパネル GUI 設定エディターを実装している。

Tk バインディングが Python インタプリターに標準で同梱されている事実がここでは重要。

エキスパートモードでは GUI は三つの盤に分かれた約 60 の属性の編集を支援する。属性編集用チェックボックス、ラジオボタン、テキストフィールド、スクロールリストボックスなどがある。

Despite this complexity, the first fully-functional version of the configurator took me less than a week to design and code, counting the four days it took to learn Python and Tk.

A Large Python Case Study: PIL

PIL は Pillow の前身パッケージだ。概要は省略する。

PIL の実装は Python インタプリターにロード可能オブジェクトコード拡張で Python を容易に拡張できる方法を示している。

  • ビットマップオブジェクトに対する基本的な操作を実装するライブラリーの核心部は速 度のために C で書かれている。
  • 高水準や手順ロジックは Python で書かれており、速度は遅いが読み込みや変更、拡張 ははるかに容易だ。

類似のツールキットを他言語で書くとどうだろう:

  • Emacs Lisp やシェルで書くのは難しいか不可能だろう。
  • Tcl には優れた C 拡張機能があるが、PIL は不快なほど大きなプロジェクトになる。
  • Perl にはそのような機能があるが、Python と比べると即興的、文書が乏しく、複雑、 不安定だ。
  • Java の Native Method Interface は Python とほぼ同等の機能を搭載しているように 見える。

Java

Java は 1995 年に登場した。

Java は «write once, run anywhere» であるように設計され、どの Web ブラウザーからでも実行可能な対話的プログラム(アプレット)を Web ページに埋め込むことを支援するものだった。その所有者である Sun Microsystems 社による一連の技術的&戦略的失策のせいで、当初の目的のどちらも果たせなかった。

  • C++ よりはるかに小さく単純
  • 自動メモリー管理
  • オブジェクト指向設計を支援
  • 構文は C 言語似
  • C 言語への呼び出しと、C 言語からの Java 呼び出しを支援

Python などに較べて十分な点も不十分な点もある:

  • クラス可視性と暗黙的スコープ規則はゆがんでいる。
  • interface 機能は多重継承の複雑な問題を回避する。ただし理解難度、使用難度はわ ずかしか下がらない。
  • 内部クラスや匿名クラスのような機能はコードが混乱する可能性がある。
  • デストラクターが欠けているため、メモリー以外の資源を適切に管理することが難しい。
  • Unix OS 機能の重要部分は純正 Java からアクセス不能。
  • I/O 機能は強力だが、テキストファイルの単純な読み込みが単純でない。

Note

軽く調査した限りでは、最近の Java は資源管理用の try 文を支援するようだ。

Java には異なるバージョンのライブラリーを管理する方法がない。このような問題に対する唯一の対処法は環境変数 CLASSPATH であり、慢性的な配備問題の原因となっている。

Sadly, browser applets are dead. Microsoft's decision not to support Java 1.2 in Internet Explorer effectively killed them.

Java は Web アプリケーションサーバー内で実行される servelet という安全な住処を得たようだ。

全体として、システムプログラミングと速度が要求されるアプリケーションを除けば、 Java は C++ より優れていると判断できる。経験上、Java プログラマーは C++ プログラマーに比べて、過剰なオブジェクト指向多層化の罠に陥る可能性がやや低いようだ。

The best single reference on paper is probably Java In A Nutshell, but (...)

Java の実装はすべての Unix, Windows, MacOS, その他多くのプラットフォームで利用可能。

Java の移植性は言語レベルでは優れている。

Java の最も優れた点は、それ自体が OS に依存しない環境として有用なほど、«write once, run anywhere» の実現に近づいていることだ。

Note

古びたことが明らかな記述は読まずに捨てた。

Case Study: FreeNet

Freenet は検閲や発禁を不可能にすることを目的とした peer-to-peer ネットワーキングプロジェクトだ。開発者の想定するアプリケーションは次のとおり:

  • 物議を醸すような情報を検閲なしに流布する。草の根ジャーナリズムから暴露記事に至 るまで、匿名かつ検閲不可能な公表を可能にすることで、言論の自由を保護する。
  • 広帯域コンテンツの効率的な配信。Debian Linux ソフトウェア更新の配布に利用され ているのと同じ機能を用いる。
  • 万人の個人的出版。たとえ発信者になりたい人が計算機を所有していなくて も、余地制限や強制的な広告なしに、誰でも Web サイトを持つことを可能にする。

Java がこのプロジェクトに適していた理由は少なくとも二つある:

  • プロジェクト目標が可能な限り多様な計算機上で互換性のある実装をすることに重きを 置いているため、Java の高い移植性が圧倒的な優位性を持つ。
  • プロジェクトの性質上、ネットワーク API が重要であり、Java には強力なものが組み 込まれている。

他言語でこのプロジェクトを取り組んでいたら:

  • C/C++ は、高性能が要求されるインフラプロジェクトでは伝統的な言語だが、標準化さ れたネットワーク API がないため、かなり困難。
  • Tcl, Perl, Python であれば性能面で大きな犠牲を払うことになる。
  • Emacs Lisp は苦痛を伴うほど遅く、まったく不適切。

Emacs Lisp

Emacs Lisp は Emacs の動作をプログラムするためのスクリプト言語だ。1984 年登場。

EmacsLisp は理論的には汎用言語として使用できるほど強力ですが、伝統的には Emacs自体の制御プログラムを記述するにとどまり、最新のスクリプト言語のように他のソフトウェアと流暢に通信することはできない。

それでも、Emacs Lisp が他の何よりも効果的なアプリケーションはかなりある。その多くは、C コンパイラーやリンカー、make(1), バージョン管理システム、デバッガーなどの開発道具のフロントエンドを使用可能にすることに関係している (Chapter 15)。

より一般的には、Emacs はパターンや構文指向の対話型編集に適している。特殊なファイル形式やテキストデータベースを対話的にハックするようなアプリケーションはメジャーモードとして原型を作成するのに最適な候補となる。

テキストエディターと密接に統合する必要があるアプリケーションや、何らかの編集機能を持つテキストビューワーとして主に機能するアプリケーションの構築にも有用だ。メールや Usenet ニュースの UA がこの区分に入る。ある種のデータベースフロントエンドも当てはまる。

メモリーを自動的に管理し、従来の言語のほとんどよりもはるかにこなれていて強力である型破りな言語だ。Java や Python に対抗できるし、C/C++, Perl, シェル、Tcl にも引けを取らない。

Lisp には長年の問題が二つあった:

  • 移植性のための、標準化された OS binding の欠如
  • 資源の浪費

これらはそれぞれ解決されたり、現代では問題にならなかったりする。

The definitive Emacs Lisp reference is The GNU Emacs Lisp Reference Manual, which may be browseable through your Emacs's info help system. If not, it can be downloaded from the FSF FTP site.

Emacs Lisp プログラムの移植性はたいそう優れている。Emacs の実装はすべての Unix, Windows, Mac OS で利用可能だ。

  • 長所:優れた土台言語である Lisp とテキスト操作のための強力な領域根源を組み合わ せていること
  • 短所:性能の低さと
  • 短所:他のプログラムとの通信の難しさ

Table 14.1 は 2003 年 3 月現在の言語使用の大まかな分布を示している。SourceForge と Freshmeat を使用。

Note

Freshmeat はおそらく名前を変えて Freecode になったものと考えられる。

Notably, SourceForge's query interface doesn't permit filtering on OS and language simultaneously, so some of these numbers represent MacOS and Windows projects.

現代の UI では OS と言語の同時絞り込みも考慮されているように見える。

Freshmeat の標本は小さいが、このサイトは Unix ベースのリリースしかない。そのため、Windows プロジェクトがないために比率が低くなると予想されるケース (C++, Java) を除いて、母集団の数字が SourceForge の数字とほぼ 1:2 の比率で一致しているのは興味深い。

この章が起草されたのは 1997 年で、執筆時は 2003 年半ばだ。これは十分に長い時間ベースであり、上記の言語の相対的な位置は最初に書いたときからいくらか変化している。

  • C, C++, Emacs Lisp はこの期間は安定
  • C は FORTRAN なぞの従来型言語を食いつつ占有率を伸ばしている。
  • C++ は Java にやや差をつけられている。

Perl はそれなりに伸びているが、言語自体はしばらく停滞している。

Tcl は相対的に衰退し、少なくとも知名度は低下している。Tcl は電子設計自動化、ラジオ・テレビ放送、映画産業など、いくつかの産業で特殊な部品のスクリプティングに広く使用されているという話がある。

Python の人気は Tcl が落ちたのと同じくらい急速に高まっている。 Perl の共同体はまだ Python の二倍の規模だが、Perl の優秀なハッカーが Python に移行する傾向が目に見えていることは、Python にとってむしろ不吉なことだ。

Java は 1997 年当時よりもわずかに普及しているに過ぎない。Linux や、より広範なオープンソース共同体のもとで、他の場所で C 言語に対して行ったような前進を Java は遂げていない。

今回調査した言語に本気で挑戦するような新しい汎用言語は現れていない。

  • PHP は Perl の CGI に挑み、Web 開発に浸透しつつあるが、ネットワークが絡まない プログラミングに使われることはほとんどない。
  • 非 Emacs Lisp 方言は衰退の一途をたどっている。
  • Ruby や Squeak といった最近の取り組みは有望に見えるが、今のところ開発グループ 以外のハッカーを惹きつけることも、持続力を示すこともできていない。

ここで勝手に 2025 年のある時点での SourceForge の言語別占有率を調べる。著者の当時の分析や見通しが現代でどれだけ通用するかを検討したい:

Language 2025 2003
Java 43,690 8,032
C++ 36,173 9,880
C 27,218 10,296
PHP 23,506 ?
Python 16,701 2,222
Perl 8,272 4,394
Shell 4,428 1,058
Ruby 1,772 ?
Tcl 1,211 649
Lisp 387 ?
Common Lisp 144 ?
Emacs-Lisp 127 ?
  • Java がまさかの占有率トップ。
  • C++ のほうが C よりも伸びている。当時の傾向から変わった。
  • PHP は著者の調査結果が不明だが、おそらく想像以上に躍進している。
  • Ruby は Perl, Python, PHP のいずれをも超えていない。想像どおりだろう。

ちなみに「新しい汎用言語」に相当するかどうか怪しいのも含めて、ランキングの上位にあるものを挙げておく:

  • C# 14,294
  • Visual Basic .NET 3,031
  • Go 1,677
  • Rust 506

今なら GitHub などの他サービスで数字を見るといいだろう。

Choosing an X Toolkit

言語の選択に関連する問題は GUI プログラミングに対する X ツールキットの選択だ。ツールキットの選択によって微妙に異なる格好と操作感が得られる。

X ツールキットの選択は二つの意味でアプリケーション言語の選択と関連している:

  • 優先ツールキットへのバインディングと一緒に出荷される言語がある。
  • ツールキットによっては限られた言語集合へのバインディングしか持っていない。

Java なら次のどちらかを選択することになる:

AWT
普遍的に配備されている。
Swing
より高性能、複雑、遅く、JDK 1.2/Java 2 にしかない。

Tcl を使用している場合、Tk が同梱されている。代替品を評価する意味はおそらくあまりない。

2003 年に真剣に検討すべきツールキットは次の四つだ:

  • Tk
  • GTK
  • Qt
  • wxWindows

GTK と Qt は明らかに先頭走者だ。いずれも MacOS と Windows に移植されているので、どのツールを選んでもクロスプラットフォーム開発が可能になる。

Tk の特徴:

  • この四者の中で最も古い。かつ現役だ。
  • Tcl で書かれている。
  • バインディングは Python の純正版に同梱されている。
  • Tk への言語バインディングを搭載するライブラリーは、一般的に C/C++ で利用可能だ。
  • 標準の情報表示要素が限られていて、かなり醜い。そして古い。
  • Canvas には他のツールキットではまだ困難としか言いようのない機能がある。

GTK の特徴:

  • C で書かれている。
  • Motif の代替品として誕生した。
  • GIMP を援助するために考案された。
  • 現在では GNOME プロジェクトの推奨ツールキットであり、何百ものアプリケーショ ンで使用されている。
  • この四者の中で唯一、生粋の C バインディングを持つ。
  • C++, Perl, Python 用のバインディングが利用可能。

Qt の特徴:

  • KDE プロジェクトに関連するツールキットだ。
  • Python と Perl 用のバインディングが用意されている。
  • 四者の中で設計が最も良く、表現力の高い API を備えているという評判だ。

wxWindow の特徴:

  • C++ で書かれている。
  • Perl や Python でのバインディングも可能。
  • 開発者たちはクロスプラットフォーム開発の支援を強調している。
  • 実際には各プラットフォームの OS 情報表示要素のラッパーであるため、それを使って 書かれたアプリケーションは OS に即した格好と使いやすさを保持する。

建築学的には、これらのライブラリーはすべてほぼ同じ抽象化水準で書かれている。GTK と Qt はイベント処理にスロット&シグナル方式を採用しており、両者間の移植はほとんど些細なことだと報告されているほど似ている。これらの中からどれを選ぶかは、選択した開発言語へのバインディングが利用可能かどうかによって決まるだろう。