まつもと ゆきひろです.

例外の話が出ましたので,もうちょっと詳しい話をしましょう.

# そもそも例外とはなんだと思っている方もいらっしゃるかも知れ
# ませんが,これについては後で(いつか)説明しましょう.

1. system callから発生する例外

  rubyはsystem callが負の値を返すと例外を発生するようになっ
  ています.この時の $! の値は perror() の出力する文字列と同
  じです.つまり,perror() で出力される文字列です.

  これらはrubyのドキュメントには載っていませんが(いつか載せ
  ます),<errno.h>を見ると載っています.

2.なぜrubyの例外処理はああなのか

  一応いろいろ考えた結果ああなっているわけです.ここで説明し
  ましょう.

  例外が発生した時にその対応としては以下のような場合が考えら
  れます.

   (1) その場でプログラムを中断する
   (2) 例外の種類にかかわらず,なんらかの対応を行う
   (3) 例外の種類毎に,それぞれ別の対応を行う

  1の場合にはrubyの場合何もする必要はありません.勝手にエラー
  メッセージを出してプログラムを中断してくれます.

  2の場合,現在のrescueの仕様でなんの問題もありません.

  3の場合は変数 $! に例外情報が文字列で入っているので,それ
  によって分岐する必要があります.また例外の種別以外に何らか
  の情報が必要であれば,大域変数などを使ってなんとかして情報
  を渡す必要があります.

  今,話題に登っているのは,3の場合にいろいろと面倒だ,と言
  うものです(よね).

  でも,私の経験からは普通にrubyを使っている場合,ほとんどの
  ケースは1または2で対応できてしまうので,3のケースはそれほ
  ど多くない気がしています.

  実際,私の書いたかなりのコードではrescueよりもensureの方が
  多用されていますし,rescueを使ってもそのあと例外の種類に応
  じて分岐することが必要だったことはそれほどありませんでした.
  言い替えると私の書いた例外処理のほとんどは「xxxという処理
  が行われなかったことに対応する」コードまたは「例外が起きて
  もyyyという処理が行われることを保証する」コードで,「xxxと
  いう処理がzzzという原因でできなかったことに対応する」コー
  ドでは無かったようです.

  一例をあげると「サーバがクライアントの処理中に例外を発生さ
  せたので,クライアントのソケットをクローズする」ような場合
  があるでしょう.この時の例外の原因は,クライアントが落ちた
  のでも,クライアントが間違ったプロトコルで通信したのでも,
  サーバプログラムのバグでもなんでも結局は同じことです.エラー
  ログには $! の値を出力しておけばデバッグ用の情報もばっちり
  です.

  いや,もちろん厳密には例外の原因によっていろいろできるので
  しょうけど,大体の場合にはこれで実用上十分だと思います.

  というわけで,*私は*例外処理には1,2のケースが十分多く,3
  はむしろまれなケースであると認識しています(勝手な認識では
  ありますが).もっとも私の限られた経験からでは断言はできま
  せんけど.

  一応,傍証をあげれば,IconとEiffelの例があります.

  Iconという言語には例外(というか失敗)があって,これには種類
  の情報が全くついていません.ただ失敗するだけです.でもちゃ
  んと使えるようです.Iconの場合には徹底していて,失敗が偽で
  それ以外の値が全て真になっています.

  Eiffelという言語はなかなか大胆な部分で機能を切り落としてい
  る言語なんですけど(例えば大域変数だとか,クラス変数だとか
  が無い),この言語にも例外に種類の情報がついていません.
  rescueという単語から,rubyへのEiffelの影響を見抜いた人は鋭
  すぎます.

  rubyの例外も「例外が発生した」というのがメインで,例外の種
  別の情報($!)はむしろ付加的な情報であるような気がします.

3.歴史の時間

  そもそもrubyの開発に取り掛かる前から,次に設計する言語には
  例外をつけようと思っていました.むかしBitという雑誌にCLUと
  いう言語に関する連載がありまして,それの影響を受けたのが直
  接の原因です.

  で,rubyを設計していた時のメモを引っ張りだしてみると,4種
  類の例外案が載っています(3年前の5月のものです).

    * Icon式例外(失敗が偽)
    * 単純型(今のrubyのもの)
    * 名前つき例外
    * 名前つき値あり例外(CLU式)

  んで,結局上で述べたように,rubyの対象とする領域では個々の
  例外を区別する必要はそれほど無くて,例外処理機能は単純なも
  ので良いだろうとの結論を出したわけです.その決断が正しかっ
  たかどうかはまだ結論は出ていないようですが,個人的にはCLU
  式の例外処理(今はC++やJavaもこのタイプの例外機能を持ってい
  ますね)よりも「お手軽」で良いと思っています.

# この時のメモは結構面白くて,rubyの仕様がまだ固まっていない
# 時の迷いが感じられますし,今ある機能がどういう過程で決まっ
# て行ったのかが良く分かります.またいつか紹介しましょう.

というようなわけで,私はrubyの例外機能はあのままで良くて,た
だドキュメントには(いつか)メソッドが発生させうる例外をきちん
と明示した方が良いと思うのです.少なくとも,あるメソッドが例
外を発生させうるかどうかという情報は必須ですね.今はそれさえ
ないものがあるので.
                                まつもと ゆきひろ /:|)