読者です 読者をやめる 読者になる 読者になる

ちなみに

火曜日の空は僕を押しつぶした。

Comparable#== が <=> の例外を黙殺しなくなる件について

仕事で使っている 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]