[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にします.上に
示した仕様のものは既に動作していますが,皆様からのコメントを
受けて見直してから公開しようと思います.

# 先に公開して実際に使ってもらってコメントをもらった方が良い
# かも知れませんけど.
                                まつもと ゆきひろ /:|)

In This Thread

Prev Next