仕事で使っている Gem が Ruby 2.2.0-preview1 で動かすと以下のような警告を出すようになった。
Comparable#== will no more rescue exceptions of #<=> in the next release.
Comparable#== は <=> の定義を使ってオブジェクトが同一かを調べる。<=> が 0 を返した場合は、同じオブジェクトであると判断するようになっている。
ところでドキュメントを読むと以下のような記述がある。
Even if obj <=> other raised an exception, the exception is ignored and returns false.
<=> が例外を吐いた場合は例外を無視した上で false を返す。
これは例えば以下のような場合に有効だった。
class A def <=>(other) self.value <=> other.value end end a = A.new p a == nil #=> false p a <=> nil #=> undefined method `value' for #<A:0x007fe19b8f6d38> (NoMethodError)
A のインスタントと value メソッドを持たないオブジェクトを比較したときに undefined method の例外を吐くが、== ではその例外は握りつぶされる。
しかし、どうも 2.2.0 以降ではこの挙動がなくなる可能性があるらしく、警告が出るようになっている。
今後は対象のチェックをさぼると == 呼んだだけでエラーになってしまう可能性があるので、比較するときはちゃんと有効なオブジェクトが対象かどうかチェックするようにした方が良さそう。
class A def <=>(other) return nil unless other.kind_of?(A) self.value <=> other.value end end
(修正:ブコメ受けてコード修正しました。return nil if other.kind_of?(A) になってました。)
nil を返すとこの2つのオブジェクトは比較出来ませんという意味になる。
see also: https://bugs.ruby-lang.org/issues/7688
今日のBGM:
![aisatsana [102] aisatsana [102]](http://cdn.image.st-hatena.com/image/scale/beb6d5e75f828edff9ee309cc2822b53f9c07fb1/enlarge=0;height=200;version=1;width=200/http%3A%2F%2Fa1.mzstatic.com%2Fus%2Fr30%2FMusic1%2Fv4%2Feb%2F60%2F04%2Feb600461-6436-e106-679c-aa838b4ac819%2F4523132113449.100x100-75.jpg)
