Exceptions(Joel Spolsky氏の記事より)

この記事
間違ったコードは間違って見えるようにする - The Joel on Software Translation Project
の下のほうに

終わる前に、もうひとつ約束していることがあった。もう一度例外を攻撃するということだ。前にやったときには、すごいトラブルに見舞われた。Joel on Softwareのホームページに即席のコメントで例外が嫌いだと書いた。例外は実質的に見えないgotoであり、目に見えるgotoよりいっそう悪いという議論をしたのだ。もちろん何百万という人々が私ののど元に飛びかかってきた。私の擁護に立ち上がった唯一の人間は、もちろんレイモンド・チェンで、彼は世界最高のプログラマなわけだから、それは意味のあることなはずだ。そうだよね?

という記述があったので、その中のリンク先を翻訳してみました。

私がこの記事に言及するのは初めてではなくて、拙著「プログラミング言語を作る」の中でも部分的に引用しています(p.341)。
よろしければそちらもどうぞ。(宣伝)

原文へのリンク
http://www.joelonsoftware.com/items/2003/10/13.html

People have asked why I don't like programming with exceptions. In both Java and C++, my policy is:

人々が私に、私がなぜ例外を使うプログラミングを好まないのか、と聞いたことがある。JavaC++の両方において、私のポリシーはこうだ。

  1. Never throw an exception of my own
  2. Always catch any possible exception that might be thrown by a library I'm using on the same line as it is thrown and deal with it immediately.
  1. 自分では絶対に例外を投げない。
  2. 使用しているライブラリにが投げる可能性があるすべての例外は、常にそれを投げられたのと同じ行でcatchし、即座に対応する。

The reasoning is that I consider exceptions to be no better than "goto's", considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto's:

そのようにする論拠は、私が例外を、コード上のある箇所から別の箇所までの突然のジャンプを作り出してしまうという点で、1960年代から有害と考えられてきたgotoよりもよいものだとは考えていないからだ。実のところ例外はgotoよりかなり悪い。

  1. They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs.
  2. They create too many possible exit points for a function. To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about.
  1. 例外はコード上で見えない。例外を投げるかもしれないし投げないかもしれない関数を含むコードブロックを見たとき、そこからどの例外が投げられるのかどうかを知る手段はない。これは、いかに注意深くコードの精査を行っても、潜在バグを検出できないということを意味する。
  2. 例外は関数に多くの「脱出口」を作り出す。正しいコードを書くには、あなたは自分の関数内のあらゆるコードの実行経路について本当に考慮しなければならない。例外を上げるかもしれない関数を呼び、それをその場でcatchしないときはいつも、あなたは、データを整合性のない状態にしたまま突然中断された関数や、あなたが考慮しなかった別のコードの実行経路による驚くようなバグが発生する機会を作り出しているのだ。

A better alternative is to have your functions return error values when things go wrong, and to deal with these explicitly, no matter how verbose it might be. It is true that what should be a simple 3 line program often blossoms to 48 lines when you put in good error checking, but that's life, and papering it over with exceptions does not make your program more robust.

よりよい代替手段は、何かがおかしくなったときは戻り値としてエラーを返し、それに明示的に対処することだ。それがどんなに冗長になったとしても。シンプルな3行のプログラムであるべきものが、適切なエラーチェックを入れたら48行になってしまうということはしばしばあるというのは事実だが、それが人生というものであり、例外でそれを取り繕ってもあなたのプログラムを頑健にしてくれはしないのだ。

I think the reason programmers in C/C++/Java style languages have been attracted to exceptions is simply because the syntax does not have a concise way to call a function that returns multiple values, so it's hard to write a function that either produces a return value or returns an error. (The only languages I have used extensively that do let you return multiple values nicely are ML and Haskell.) In C/C++/Java style languages one way you can handle errors is to use the real return value for a result status, and if you have anything you want to return, use an OUT parameter to do that. This has the unforunate side effect of making it impossible to nest function calls, so result = f(g(x)) must become:

C/C++/Javaスタイルの言語を使っているプログラマが例外に惹きつけられた理由は、単純に、文法が複数の値を返す関数を呼び出す簡単な方法を持たないため、戻り値とエラーのどちらか一方を返す関数が書きにくかったからではないかと私は考える(私が手広く使った中で、複数の値をうまく返させてくれる言語はMLとHaskellだけだ)。C/C++/Javaスタイルの言語では、あなたがエラーをハンドルできるひとつの方法は、真の戻り値を結果ステータスとして使うことであり、かつ、何であれ関数から返したいものはOUTパラメタを使うことだ。これには、関数呼び出しのネストが不可能になるという不幸な副作用がある。result = f(g(x))は、こう書かなければいけない。

T tmp;
if (ERROR == g(x, tmp))
     errorhandling;
if (ERROR == f(tmp, result))
     errorhandling;

This is ugly and annoying but it's better than getting magic unexpected gotos sprinkled throughout your code at unpredictable places.

これは醜いしうっとうしいが、予測できない魔法のgotoを、あなたのコードの全域にわたって、予想不能な箇所にばらまくよりはマシだ*1

感想

言わんとするところはわからなくはないのですが、個人的には全然賛同できません。
戻り値でちまちまエラーケースを上位に戻していってうまくいくと思えるほど、私は(自分を含む)プログラマを信用していない、ということなんだと思います。だからcrowbarにもDiksamにも例外処理機構を入れました。
プログラミング言語を作る」中でも例を挙げていますけど、確かに例外で処理がブッチされることでデータ構造が壊れることはあり得ます。じゃあ戻り値ちまちま方式ならそれが防げるかと言うとそうとも思えないし、どっかで対処を怠り例外をもみ消してしまう危険の方が高いと思います。

*1:at unpredicable placesがどこにかかるのかよくわかりませんでした……(2010/1/7追記:yuyaさんのコメント参照のこと。)