[#380] bug report#3 and request#5 — keiju@... (Keiju ISHITSUKA)
けいじゅ@SHLジャパンです.
1 message
1996/08/06
[ruby-list:422] exception spec
From:
matz@... (Yukihiro Matsumoto)
Date:
1996-08-21 04:06:24 UTC
List:
ruby-list #422
まつもと ゆきひろです
で,いろいろ考えた結果,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にします.上に
示した仕様のものは既に動作していますが,皆様からのコメントを
受けて見直してから公開しようと思います.
# 先に公開して実際に使ってもらってコメントをもらった方が良い
# かも知れませんけど.
まつもと ゆきひろ /:|)