トップ «前の日記(2018-12-26) 最新 次の日記(2018-12-30)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2018-12-27

_ Rubyで例外クラスを定義する

次のスクリプトは不思議な動作をする。
class TestError < RuntimeError
  def to_str
    "foobar" 
  end
end
 
begin
  raise TestError.new('hello')
rescue TestError => e
  puts 'OK'
rescue => e
  puts e.class    #=> RuntimeError
  puts e.message  #=> foobar
end

なぜかRuntimeErrorに変わってしまう。もちろんクラス指定でrescueはできない。

これは仕様なのかバグなのかよくわからないが、理由は、raiseの第1引数がStringだと判断されてしまうからだ。というのは、TestErrorクラスにto_strが実装されているからだ。

これが仕様(raiseに第1引数はto_str実装クラスを含むStringの一種ならばそれをmessageに持つRuntimeErrorをスローする)なのか、バグあるいは親切にしすぎ(間違えてHashやArrayを渡された場合にto_strすることで救済する)なのかはどちらでも良い気がするが、つまるところ、例外クラスを独自に作成する場合は、to_strメソッドを実装してはだめということだ。定義した瞬間にそのクラスは意味がなくなる(上の例なら黙ってraise 'foobar'を実行すれば良いことになる)からだ。

本日のツッコミ(全5件) [ツッコミを入れる]
_ naruse (2018-12-28 07:38)

to_sならともかく、to_strは暗黙の変換なのですから定義したら異常なことになるのは当然でしょう

_ arton (2018-12-28 08:16)

そう来るとは思わなかったけど(to_strがやばいメソッドだというのはその通りだが)、 <br>@@ -768,6 +768,8 @@ <br> exc = argv[0]; <br> if (NIL_P(exc)) <br> break; <br>+ if (rb_obj_is_kind_of(exc, rb_eException)) <br>+ goto exception_call; <br> if (isstr) { <br> mesg = rb_check_string_type(exc); <br> if (!NIL_P(mesg)) { <br>のほうが良くない?

_ arton (2018-12-28 08:21)

と、パッチを作ったわけだが、そもそもわざとException派生かどうかよりもto_strを優先しているかを知りたかったのだけど、成瀬さんの「当然」というのはto_str優先に思えるけど、「異常」だというのも認識のうちなら異常じゃないようにすれば良いんだからパッチを当てるべきな気もするなぁ。

_ naruse (2018-12-28 21:28)

異常なことをする人のためにわざわざ処理を追加する必要はあんまり感じないかなぁ。 <br>というスタンスの人がおそらく多いので、そもそもException派生かto_str優先かは処理系およびバージョン依存という感覚で、変えて速くなるなら変えるけど、わざわざいじって遅くするモチベーションはない感じ

_ arton (2018-12-29 20:37)

まあ、そうですね(というか、そこに同意できなければredmineに書いてるわけだし)。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|

ジェズイットを見習え