From: matz@... (Yukihiro Matsumoto) Date: 1996-08-21T13:06:24+09:00 Subject: [ruby-list:422] exception spec まつもと ゆきひろです で,いろいろ考えた結果,rubyの例外の仕様を以下のようにするこ とにしました.御意見をお待ちします. # 石塚さんには満足して頂けると思います. (1) 変数 $! の値は文字列から例外オブジェクトに変更した exitとinterruptも統合したので,正確に言うと「例外」では なく,「大域脱出」です. で,工夫した点は「大域脱出オブジェクト」が文字列のサブク ラスである点です.文字列として扱う場合には今までと全く同 じに使えます. 大域脱出のクラス階層は以下のようになっています.これは基 本的にpythonを参考にしました.より適切な名前や階層があれ ば変更します. Object String GlobalExit SystemExit Interrupt Exception SyntaxError TypeError ArgumentError NameError IndexError RuntimeError ZeroDivisionError SystemCallError Errno::ENOENT ... 大機脱出の同定は kind_of? を用いて行いますので,例えば NameErrorという例外は,NameErrorとしてもExceptionとして もGlobalExitとしても捕捉できます. クラス階層を見るとSystemCallErrorの下にErrno::ENOENTとい うような例外がありますが,これはlinuxのerrno.hを元に生成 しました.linux以外のOSでは定義されないものや逆に名前が 与えられないものがある可能性は否定できませんが,ほとんど の場合はカバーされるはずです. 移植性を非常に気にする人はこれらの定数を使う前に defined?(Errno::ENOENT) のような方法でチェックしておくと完璧でしょう. (2) resuceの構文の変更 いままでrescueは全ての例外を捕捉していましたが,構文を変 更して捕捉する例外を指定できるようにしました.指定を省略 すると今まで通り全ての例外を捕捉します(がexitとinterrupt は捕捉しない).また一つのbegin文に複数のrescue節を指定で きるようにしました. 例: begin ... rescue SyntaxError, IndexError ... rescue Interrupt ... end また例外以外の大域脱出(exitとinterrupt)もrescueで捕捉で きるようになりました.同じ大域脱出でもthrowはrescueでは 捕捉できませんので,今まで通りcatchを使ってください. (3) raise rubyの中から例外も発生するメソッドはfailからraiseに変わ りました.APIは raise # 最後の例外の再発生 raise 文字列 # RuntimeErrorを起こす raise 例外 # 「例外」を起こす raise 例外クラス, 文字列 # 指定したクラスの例外を起こす です. ただし,failはraiseの別名として今でも使えます.以前のプ ログラムはみな正常に動くはずです.fail!は無くなりました. raise!はまだありません.しばらく使ってみてやはり必要なよ うなら追加します. (4) C I/F 拡張モジュールから呼ぶためのAPIは以下のものがあります. * 既定義例外の発生 TypeError(fmt, ...) 型が合わない時の例外 ArgError(fmt, ...) 引数が合わない時の例外 NameError(fmt, ...) 属性,変数が定義されない時の例外 IndexError(fmt, ...) Indexが正常の範囲内に無い時の例外 Fail(fmt, ...) RuntimeErrorを発生させる.とりあえず例外を定義するの が面倒な場合や過去の互換性のために使う. rb_sys_fail(mesg) システムコールが失敗した時適切な例外を発生させる. mesgはメッセージに埋め込む文字列(または0). * 例外の定義 既に説明したように,例外はクラスですから,新しい例外を 定義すると言うことは新しいクラスを定義することです.た いていはGlobalExitかExceptionのサブクラスとして定義し ます.rubyの処理系ではCから eXXXX という識別子で参照で きるようなルールを使っています. 例: extern VALUE eException; eKeyError = rb_define_class("KeyError", eException); * 例外の発生 Raise(etype, fmt, ...) etypeのクラスの例外を発生させる.メッセージはprintf 形式で指定する rb_raise(exception) 例外オブジェクトを指定して例外を発生させる. (5) 標準ライブラリが適当な例外を発生するように rubyの標準ライブラリで例外発生させている部分で,簡単に決 められる部分に関しては適切な例外を発生するように書き換え ました.まだドキュメントには反映していません. # だれかドキュメントを手伝って欲しいなあ. 最終的には安易なFail()やRuntimeErrorは撤廃したいのですが, それにはもうちょっと議論が必要かもしれません. で,文法が変更されますので,バージョンを0.99.2にします.上に 示した仕様のものは既に動作していますが,皆様からのコメントを 受けて見直してから公開しようと思います. # 先に公開して実際に使ってもらってコメントをもらった方が良い # かも知れませんけど. まつもと ゆきひろ /:|)