2009年4月30日木曜日

なぜ、例外がクラス化されたのか?

原文:http://python-history.blogspot.com/2009/03/how-exceptions-came-to-be-classes.html
原文投稿者:Guido van Rossum

初期のころから、私はPythonでエラーを扱うために例外を使用したいと思っていたことを覚えている。しかし、例外を動作させるために重要なことは、異なる例外の種類を識別させるのにはどのような分類方法を利用すればいいのかというのを思いつくことである。現代的な言語は(もちろん最近のPythonも:-)、ユーザ定義クラスを使用して例外を定義する。しかし、初期のPythonはそうではなく、文字列によって例外を識別する方法が選ばれた。この選択は失敗ではあったが、この方法を選択した理由は2つあった。まず最初に、私は例外をModula-3で学んだが、この言語では例外というのは、重複のないトークンが使用されていたからである。2つめの理由としては、ユーザ定義クラスが導入される前に例外を導入したことである。

理屈の上では、私が例外のために組み込みのオブジェクトの新しい型を作るということも考えられたが、すべての組み込みオブジェクトの型はC言語上で努力してかなりの量のコーディングを行う必要があるので、私は既存の組み込み型を再利用する方を選択した。例外はエラーメッセージと結びつけられることがあるので、例外を表現するのに文字列を使用するのは自然なことであると思われた。

後から考えると失敗だったのだが、私は、異なる文字列オブジェクトが異なる例外を表現する、というやり方を選択してしまった。例え同じ内容の文字列(同じ文字の並びが含まれている文字列という意味)であっても、違うものとして認識されてしまうのである。このやり方を選択した理由としては、異なるモジュールで定義された例外は、例え同じ内容の文字列であっても、独立してそれぞれ違う例外であると区別できた方がいいだろう、と思ったからである。この考え方は、例外は常に名前(中身ではなくて変数名)で参照され、オブジェクトの同一性で判断されるだろう、との判断からである。値の一致性で見るためには文字列の中身の同一性をみる必要があるが、これを行うことはないと考えていたのである。

この方法はModula-3の例外からの影響を受けていた。Modula-3では、例外宣言があると、重複のない「例外トークン」が作られ、他の例外トークンと区別がつかなくなることはない。私は、ポインタを使って例外を比較するように最適化を行い、文字列の値の比較をなくして、実行時間を最適化しようという間違った誘惑にかられてしまった。これは珍しいケースである。私はいつも自分のコーディング時にしか最適化を行わないのだから。もっとも大きな理由は、異なるモジュールで定義された関係のない例外の名前が衝突してしまう、ということを心配したからである。このため、私は例外を使用するやり方を厳密に決める必要がある、と考えていた。まず例外をグローバルの定数としてモジュール内に定義をして、例外を上げたり、受け取ったりするときには、そのグローバル定数の名前を利用するというものである。これは、文字列リテラルが自動的に隔離するようになる、ずっと前のことである。

訳注:文字列の隔離というのは、同じ内容の文字列はメモリを共有して同じIDを持つように最適化することである。

悲しいことに、読者の方々の想像通り、実際にはこの方法はうまくいかなかった。初期のPythonユーザによって、同じ内容の文字列が合った場合に、同じモジュール内ではバイトコードコンパイラが統合してしまうことが発見された。これは、同じ文字列の値を持つ文字列リテラルがいくつも現れると、共有オブジェクトを一つだけ作る、ということである。この不具合により、例外は文字列の名前でも、エラーメッセージを含む文字リテラルの中身でも、同じように捕まえられることが判明したのである。実際には、同じモジュールの中で定義されたコードでのみ動作し、異なるモジュールの例外エラーメッセージを使って例外をキャッチしようとしても、不思議な失敗の仕方をしてしまうのである。言うまでもなく、これは広範囲にわたって混乱を発生させることになってしまった。

1997年のPython 1.5において、私は言語にクラス例外を導入した。Python 2.5まではレガシーアプリケーションをサポートするという目的で、文字列例外も残されてはいたが、クラス例外が推奨されることとなった。そして、Python 2.6において、最終的に文字列例外は姿を消したのである。

0 件のコメント:

コメントを投稿