==とequal?とeql?と===の違い
前回のやつでArray#-を独自定義したクラスで使うためにはeql?メソッドのオーバーロードが必要そうなのだけど、いろいろ似たようなのがあって紛らわしいのでRubyリファレンスで調べてみた。
Object#==
self==(other)
self と other が等しければ真を返します。デフォルトでは equal? と同じ効果です。
このメソッドは各クラスの性質に合わせて再定義するべきです。
と一般的にはこれをオーバーロードするのが良いらしい。
Object#equal?
equal?(other)
other が self 自身の時、真を返します。
このメソッドを再定義してはいけません。
ということで再定義は不可らしい。
irbで実験してみると
irb(main):001:0> a = "hoge" => "hoge" irb(main):002:0> b = "hoge" => "hoge" irb(main):003:0> a == b => true irb(main):004:0> a.equal? b => false irb(main):005:0> b.equal? a => false
ということでObject#object_idを見て比較しているものと思われます。
eql?
それで、次が問題のeql?なわけですが、
eql?(other)
二つのオブジェクトが等しければ真を返します。Hash で二つのキーが等しいかどうかを判定するのに使われます。
このメソッドを再定義した時には Object#hash メソッドも再定義しなければなりません。
eql? のデフォルトの定義は equal? と同じくオブジェクトの同一性判定になっています。
ということでObject#hashをみて比較しているようです。よく分からないのでObject#hashを調べてみると、
ということでチェックの厳しさではeql? > == ということでよいのかな…。
「The Ruby Way」のp.251によると、
eql?は、==と同様に、レシーバと引数を比較しますが、こちらの方がわずかに几帳面です。たとえば、==を使って比較する場合、異なる数値オブジェクトは強制的に共通のタイプに変換されますが、eql?では、異なるタイプの数字に対する等価性のテストは行なわれません。
型が異なると即座にfalseが返されることから、引数にレシーバと同じオブジェクトを取るようなメソッドの場合にeql?を使うのが良さそうです。
Object#===
self===(other)
このメソッドは case 文での比較に用いられます。デフォルトは Object#== と同じ働きをしますが、この挙動はサブクラスで所属性のチェックを実現するため適宜再定義されます。
クラスのインスタンスかどうかチェックするときに使うそうです。
なんか分かったような分からないような…。。。