けいじゅ@SHLジャパンです. 

In [ruby-list :00407 ] the message: "[ruby-list:407] Re: about
exception ", on Aug/13 01:10(JST) matz / caelum.co.jp (Yukihiro
Matsumoto) writes:

>長いです.

ながすぎます. 

>|例を挙げれば, File.open() などは, 例外で対処すべきものではないのかも知
>|れません. indexとかと同じで nil を帰すようにするわけですね. 
>
>バランスの見直しはあるいは必要かも知れませんが,File.openに
>関しては私は賛成できません.というのも,File.openが失敗した
>場合,nilを返すと言うことは結局必ず例外処理のコードを書かな
>いといけなくなることを意味します(でないとnilにメッセージを送っ
>てエラーになり,現在よりもエラーメッセージが分かりにくくなる).
>それは避けたいです.
>
>  file = File.open(fname)
>
>だけでもちゃんと動き(例外が起こればそれに応じたメッセージが
>表示され),例外処理をすればそれなりに対処できるものでないと.

File.openはただの例ですから, あまり気にしないで下さい. 

ここで示された例外に関する指針は,

1. そのメソッドは通常では正しく終了する.
2. 正しく動くことが, はっきりしていれば, 例外の記述はいらない.
3. 異常が発生した時は, 必ず例外の対処を必要とする.

というものですかね?

string#index() のようなものは, (1)もはっきりしていないし, 必ずその後 
検索位置を調べるので例外でなくて良いということですかね?

># そういう意味ではEOFは例外の方が良かったかも知れない.

先の条件を EOF というか EOF を発生しそうな関数(例えばgets)に当てはめる
と, (1), (2), (3)ともに満たしますね...

確かに, 今の IO#gets() の仕様は, 読み込んだ文字列を必ず nil かどうか判
断しなくてはいけない仕様になっている... 

でも, 

whle (line = file.gets) ...

のような時は, 例外が発生しない方が面倒くさくないともいえるなあ... 

まあ, while(line = file.gets) ... のような使い方は,

for line in file 

とするとすれば問題はなくなるかな?

>今まで話した中で,現在の例外の仕様で問題があると思われた点は
>以下のものがあります.
>
>  (1) Interruptがデフォルトで例外に変換されるので,思わぬ
>      rescueで捕捉されてしまう.
>
>  (2) 変数名/メソッド名のスペルミスなどの思わぬ例外もrescue
>      で捕捉されてしまう.
>
>  (3) UNIX間はともかく他のOSに移植された時に例外のメッセージ
>      が変わってしまう可能性がある.
>
>  (4) 例外メッセージにスペルミスがあってもコンパイル時に検出
>      できない.あるいは意味的に同じ例外に違うメッセージが割
>      り当てられる可能性がある.

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

以下を追加して下さい.

(5) 異なる種類の例外に同じメッセージが割り当てられてしまう可能性が
    ある.

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

確かに, 必ず Interrput かどうか判断しなくてはいけなくなりますからね. 

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

統一の指針としては, それで良いと思います. ただし, エラーメッセージの辞
書は perror などは頼らずに, ruby 内部で独自に持つ必要がでてきますね.

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

私は, (4)ではなくて(5)を気にしたのでした.

ただ, (4)はライブラリを作る側としては, 間違いが少なくなるという効果は
あると思います.

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

文字列の分岐で何とかなるのは, そういう例外が発生するとしてコーディング
しているので, 思わぬ例外とはいえません. きっと, このようなケースは稀だ
から気にしないということですよね?

(2)に近いのですが, 問題をはっきりさせるために次の項目も挙げておきます.

(2') (ライブラリが利用している隠れた)ライブラリが出す思わぬ例外を拾って
    しまう. 

ユーザから見ると, 直接使っているクラスの例外がどのようなものかを把握す
るのは比較的容易だと思います. ライブラリが利用しているライブラリが出す
例外となるとなかなか把握するのは難しいと思います. 

たとえば, ネットワーク系のエラーなどの場合ですね. クラスFooがネットワー
クを利用したクラスとしましょう. その中のメソッドfooはある場合に, 例外X
を発行するとします. ユーザ側は例外Xはどうにか対処できるので, 対処でき
ると信じて メソッド foo に関して例外を書いたとしましょう. もし, fooを
呼び出した時に回線障害かなんかで例外が発生したのに, 例外Xだとして間違っ
た処置を行なってしまいます.

(2)も(2')も問題の原因は同じようなものだと思います. (2)よりは, (2')は文
字列で対処しやすいが, 発生の頻度は大きいというぐらいでしょうか.

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

>たぶんここが一番食い違っているところだと思います.
>
>例えば,対象が存在しなかった時のFile.openとDir.openのメッセー
>ジが全く異なっていたら,若干使いにくいかも知れませんが,本質
>的な問題だとは思えません.むしろ例えば
>
>  File.open - No such file
>  Dir.open  - No such directory
>
>の方が分かりやすい可能性だってありますよね.私には唯一性の保
>証が必要になる局面が想像できないんですけど,どういう場合が考
>えられますか?
>
>例外のメッセージが不統一になりがちだという指摘にはIDやSYMBOL
>を使っても統一する気が無ければ統一されないし,統一する気があ
>れば文字列でも統一されると答えておきます(ちょっと説得力弱い).

これに関しては, (5)のケースを言いたかったのでした.

(5)の問題は, シンボル(ID)化しても解決しないのですが... クラス毎に分割
して管理した方がよいのでは? ということを示すための問題点でした.

もしかしたら, クラスライブラリは同時に複数箇所で開発されるかも知れない
ので, メッセージを全て把握することはできないですよね? ですからクラス単
位でメッセージ(IDも)管理した方が良いということです.

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

も, というか. これが主だと思っているのですが... 

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

それは賛成します. rubyの特徴は, クラスライブラリもそれなりに作りやすい
ところにあると思っています.

あまり, 難しい例外機構はいらないでしょう.

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

# メイルの長さで良く分かります(^^;;;

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

>まず現在の例外処理の問題(の可能性)は
>  * 予想しない例外を捕捉してしまう(特にinterrupt/スペルミス)
>  * 同じ意味の例外に違うメッセージが割り当てられてしまう可能
>    性がある.
>個人的には後者を問題だとは認識していないんですけど.

(2')のことも気にして下さい. 

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

本当に, 例外の種別を気にしなくて良いのか? ということが気になります. 前
にも説明しましたが, 例外が発生した場合, 適当な処理を行ない結局終了する
のならそれで良いと思います.

何らかの処理を行なってリカバリを行ないたいのであれば, 例外の種別を気に
しないでは済まされないと思います. 特に, (2')のようなケースがあるとする
となおさらだと思うのですが?

>ここで例外にIDを導入した場合,メリットは
>  * いろいろな例外にきめ細かく対応できる.
>  * 同じ意味の例外に同じ名前(種別)を割り当てやすい

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

この辺りになると性格の違いが出てくるというか何というか...

例外処理ルーチンは, 対象となる例外以外を処理すべきでないと考えます. こ
れは, 当たり前なのですが, 言語的にもそれを行ないやすくなっている必要が
あると感じているわけです. 

>デメリットは

>  * 発生する例外を覚えている(あるいは調べる)必要がある.

例外を発生させる側ですか? それであればクラス単位で管理するとすれば問題
は減少します. 例外を受ける側では文字列でも同じだと思います. 

>  * 例外処理の記述が複雑になる.

例外処理を行ないたいのであれば, ある程度しょうがないのではと思います.

>  * 例外を発生させる人にとって面倒(例外をいちいち定義,参照
>    する必要がある).

確かにデメリットではあるのですが... 

>と言うわけで石塚さんが私を説得するストラテジーとしては,
>  + (interruptなど以外で)文字列の分岐では本質的に問題がある例
>  + (クラス毎などある単位で)例外種別を一元管理することの優位性
>を示すのがベストだと思われます.

まず,
>  + (クラス毎などある単位で)例外種別を一元管理することの優位性
から. 

(5)で述べたように, 私が主張したいのはある単位で分割管理することです.

>  + (interruptなど以外で)文字列の分岐では本質的に問題がある例

上記が満たされかつ, 例外識別/分岐のためのサポートがあれば, 文字列でも
良いのかなという気もします.

>ちなみに石塚案を元に私が新しい例外機能を設計するならばこうい
>う感じになるでしょう.
>
>class Foo<Super
>  ...
>
>  fail ENOFOO, "foo is not valid"
>  ...
>end

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

そうなんだ... しらなかった...

>受ける側では

(中略)

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

確かに, これだと, 私の主張ともあっていますし, ここまであるということは
ないのですが... さらにこれは, 従来のrescueとも互換があるわけですね.

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

まだだめ?

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

受ける側は, 上記の構文だと思って良いわけね? かつ, rescueでは文字列の比
較(==)ではなくて equal?() であれば, 文字列オブジェクトそのものが識別子
として使われることになりますね.

それであれば, 大満足です.

上記のは変数ですが, ハッシュを使うのも良いですね.

例:

IO::EXCEPT{"NOENT"} = "No such file or directory: %f"

でも, これだと

rescue IO::EXCEPT{"NOENT"}

となるのか... クラス変数の方がいいかな.

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

>まあ,単なるlisp user以上を指すlisperのような言葉もありますし….

lisper == ESPER ですかねえ...

># もっと良いのが思い付いたら是非教えてください.

調べました.
宝石(lupis)の宝石通(lupidarist)ということで, rubyistは ruby通 というこ
とでいかがでしょう?

__
..........................................石塚 圭樹@SHLジャパン(株)...
------------->アドレス変わりました!! e-mail: keiju / shljapan.co.jp <----