[ruby-list:407] Re: about exception

From: matz@... (Yukihiro Matsumoto)
Date: 1996-08-12 16:10:09 UTC
List: ruby-list #407
まつもと ゆきひろです.

長いです.

In message "[ruby-list:405] Re: about exception"
    on 96/08/12, Keiju ISHITSUKA <keiju@shljapan.co.jp> writes:
|けいじゅ@SHLジャパンです. 

|段階を追っていけばそういうことになりますよね. 現在は,
|
|  * それはどのくらい問題なのか
|
|という段階だと思っています. 

|例外の機能と 現在あるライブラリ群の例外の発生の仕方のバランス なのかな?
|という気がしています. 

|例を挙げれば, File.open() などは, 例外で対処すべきものではないのかも知
|れません. indexとかと同じで nil を帰すようにするわけですね. 

バランスの見直しはあるいは必要かも知れませんが,File.openに
関しては私は賛成できません.というのも,File.openが失敗した
場合,nilを返すと言うことは結局必ず例外処理のコードを書かな
いといけなくなることを意味します(でないとnilにメッセージを送っ
てエラーになり,現在よりもエラーメッセージが分かりにくくなる).
それは避けたいです.

  file = File.open(fname)

だけでもちゃんと動き(例外が起こればそれに応じたメッセージが
表示され),例外処理をすればそれなりに対処できるものでないと.
# そういう意味ではEOFは例外の方が良かったかも知れない.

|というわけですから, 最初のフェーズをもうちょっと考えてみましょう.

それには賛成です.

今まで話した中で,現在の例外の仕様で問題があると思われた点は
以下のものがあります.

  (1) Interruptがデフォルトで例外に変換されるので,思わぬ
      rescueで捕捉されてしまう.

  (2) 変数名/メソッド名のスペルミスなどの思わぬ例外もrescue
      で捕捉されてしまう.

  (3) UNIX間はともかく他のOSに移植された時に例外のメッセージ
      が変わってしまう可能性がある.

  (4) 例外メッセージにスペルミスがあってもコンパイル時に検出
      できない.あるいは意味的に同じ例外に違うメッセージが割
      り当てられる可能性がある.

石塚さんは他にもいくつかあげているようですが,本質的なのはこ
れらでしょう.

1は確かに問題だと思います.これはデフォルトをexitかthrowにす
る方向で検討します.

3は他のOSに移植する時にメッセージをUNIXに合わせる方向で実装
することで対応できると思います.つまり例外の仕様の問題ではな
く,実装の問題だと思います.UNIX間ならメッセージは共通である
と考えて良いでしょう.

4は私には本質的だとは思えません.たとえいくらか検出しにくい
としてもスペルミスはバグですし,あくまで実装の問題です.また,
石塚さんは意味的に同じ例外に異なったメッセージがマッピングさ
れることを問題だと感じていらっしゃるようですが,私はそれほど
問題だとは思っていません(後述).

となると残りは2ですが,これもかなりの場合は文字列の分岐でな
んとかなりそうな気がします.もっとも前のメイルにも書いたよう
にいくつかの例外は「エラー」と言う例外とは別の括りにした方が
良いかも知れないので,これは継続して検討します.

|将来的に, 色々な人がクラス/モジュールを提供する様になった場合を考えて
|みて下さい. その場合, 各々独自にメッセージを作るようになると収集がつか
|なくなる様な気がしませんか? 当然, 唯一性の保証もなくなりますし...

唯一性の保証って必要なんですか? あるいは収集がつかなくなると
はどういう事態のことですか?

たぶんここが一番食い違っているところだと思います.

例えば,対象が存在しなかった時のFile.openとDir.openのメッセー
ジが全く異なっていたら,若干使いにくいかも知れませんが,本質
的な問題だとは思えません.むしろ例えば

  File.open - No such file
  Dir.open  - No such directory

の方が分かりやすい可能性だってありますよね.私には唯一性の保
証が必要になる局面が想像できないんですけど,どういう場合が考
えられますか?

例外のメッセージが不統一になりがちだという指摘にはIDやSYMBOL
を使っても統一する気が無ければ統一されないし,統一する気があ
れば文字列でも統一されると答えておきます(ちょっと説得力弱い).

|とここまで書いて気になったのですが, 例外を発生させるのはライブラリ側が
|主であると考えているのですが, 違いますか? ライブラリとなることを目的と
|して作られたもの以外の通常のプログラム(関数など)も例外を出すことは考え
|ていませんよね?

そのような仮定は置いていません.確かに私は,OOPには単なるク
ラスライブラリの利用者としての立場とクラスライブラリ作成者の
立場があり,両方を支援すべきだと考えていますし,その考えにし
たがってrubyではクラスライブラリを利用した従来型プログラミン
グも可能なように設計されています.

しかし,同時に単なるクラスライブラリの利用者がクラスライブラ
リの作成者に簡単にステップアップできるように両者の垣根は低く
あって欲しいとも考えています.よって例外の使い方にそのような
(ライブラリ開発者だけが使うという)仮定を置きたくない気持があ
ります.

|特に, 将来のことを考えると, このぐらいの仕組みはちゃんと決めておかない
|と大変なことになるのではと心配します.

例外について良く考えることは非常に重要なことだと思います.

さて,例によってまとめておきましょう.

まず現在の例外処理の問題(の可能性)は

  * 予想しない例外を捕捉してしまう(特にinterrupt/スペルミス)
  * 同じ意味の例外に違うメッセージが割り当てられてしまう可能
    性がある.

個人的には後者を問題だとは認識していないんですけど.

そしてメリットは

  * (逆接的だが)例外の種別を気にする必要が無い
  * 仕組みが簡単で(ほとんどの場合)記述も簡単

だと思います.

ここで例外にIDを導入した場合,メリットは

  * いろいろな例外にきめ細かく対応できる.
  * 同じ意味の例外に同じ名前(種別)を割り当てやすい

私は前者はそれほど必要ないとまだ思っています.もちろん前述の
いくつかの問題については認識しましたので,なんらかの検討を行
います(が,おそらく例外とは違う枠組で対応すると思います).後
者もあまり必要だと思っていません.

デメリットは

  * 発生する例外を覚えている(あるいは調べる)必要がある.
  * 例外処理の記述が複雑になる.
  * 例外を発生させる人にとって面倒(例外をいちいち定義,参照
    する必要がある).

だと思います.

と言うわけで石塚さんが私を説得するストラテジーとしては,

  + (interruptなど以外で)文字列の分岐では本質的に問題がある例
  + (クラス毎などある単位で)例外種別を一元管理することの優位性

を示すのがベストだと思われます.


ちなみに石塚案を元に私が新しい例外機能を設計するならばこうい
う感じになるでしょう.

class Foo<Super
  ...

  fail ENOFOO, "foo is not valid"
  ...
end

などで例外を発生させ(superclassの指定は`<'です),

受ける側では

...
rescue ENOFOO, ENOBAR
    ...
rescue		# default rescue
    ...
end

となります.ここでは例外はクラスにせずsymbolで同定しています.
symbol(式としては :sym となる)とは識別子と1対1で対応する数値
です.

またはより元の石塚案に近づけるならば,

class Foo<Super
  FOO_EXCEPTION = Exception.new("foo is not valid")
  ...

  fail FOO_EXCEPTION, arg
  ...
end

などで例外を発生させ,

受ける側では

...
rescue Foo::FOO_EXCEPTION
    ...
rescue Bar::BAR_EXCEPTION
    ...
rescue Interrupt
    ...
rescue # default rescue
    ...
end

で受けるとかですね. 例外種別による分岐を前提に置くのなら,
rescueの中で分岐するより,節の文法を上のように変更した方が良
いでしょう.

|今までの互換性に関しては, 例外を受けとる側に関しては, Exception の文字
|列表現を message にしておけばそれほど問題ないと思います. 例外を出す側
|は, 種別情報をつけなくてはいけないので互換性はあまりないことになります
|ね.

例外発生側の互換性が無いのはかなりつらいなあ.それだけのメリッ
トがありそうなら喜んで変えるんだけど,それほどはメリットを感
じていないしなあ.もっと説得してくださいよ > 石塚さん

いま思い付いたんだけど

  IO::ENOENT == "No such file or directory"

などと定数で定義されていれば満足できる? もちろんFile::NOENT
でもアクセスできるとして.あと今の例外は個別の情報が埋め込ん
であるのを何とかした方が良いだろうけど.

例:

  foo
  undefined method `foo' for main(Object) 

|なるほど. では, rubyist ということで. 
|# でも, rubyのエキスパートのことではないよなあ.

まあ,単なるlisp user以上を指すlisperのような言葉もありますし….
# もっと良いのが思い付いたら是非教えてください.

                                まつもと ゆきひろ /:|)

In This Thread

Prev Next