オブジェクトの等値性

ややこしいのでメモ。

equal? ふたつの式が指すオブジェクトが同一か?
== ふたつのオブジェクトの値が等しいか?
eql? ハッシュキーが等しいかどうかチェックするために Hash クラスが使う。
=== case 文の when で使われる。
=~ 正規表現のマッチ。

equal?

a = "Ruby"          # => "Ruby"
b = "Ruby"          # => "Ruby"
c = b               # => "Ruby"

a.object_id         # => 134586220
b.object_id         # => 134585530
c.object_id         # => 134585530

a.equal? b          # => false
b.equal? c          # => true

==

a = "Ruby"          # => "Ruby"
b = "Ruby"          # => "Ruby"

a.object_id         # => 134586100
b.object_id         # => 134585530

a.equal? b          # => false
a == b              # => true

1 == 1.0            # => true
1 == "1"            # => false  # 無茶しすぎ

eql?

1 == 1.0            # => true
1.eql? 1.0          # => false

Hash ってキーとなるオブジェクトの hash を取って Fixnum として比較してるんじゃないの?

class OreOre
  def initialize(id) @id = id end
  def ==(o) @id == o.id end
  def eql?(o) self == o end
  attr_reader :id
end

o = OreOre.new(1)
p = OreOre.new(2)
q = OreOre.new(1)

o == p              # => false
o == q              # => true

o.hash              # => 134668880
p.hash              # => 134668870
q.hash              # => 134668860

o.eql? p            # => false
o.eql? q            # => true

h = {}
h[o] = "o"
h[p] = "p"
h[q] = "q"
h.size              # => 3
h                   # => {#<OreOre:0x100dc4a0 @id=1>=>"o", #<OreOre:0x100dc48c @id=2>=>"p", #<OreOre:0x100dc478 @id=1>=>"q"}

やっぱり o.hash がキーになってるっぽい。

オレオレクラスを作ったときの ==, hash, eql? の関係は?
eql? を == 相等にしたら、hash はどうやって作ればいいのだろうか?

===

when でウマくマッチするようにする。

def foo(x)
  case x
  when (0..9)
    "0..9"
  when /\d{2}/
    "/\d{2}/"
  when Fixnum
    "Fixnum"
  end
end

foo 5               # => "0..9"
foo 99              # => "Fixnum"
foo "99"            # => "/d{2}/"
foo :foo            # => nil

=~

s = "Ruby"
/r/i =~ s           # => 0
/u/i =~ s           # => 1
/b/i =~ s           # => 2
/y/i =~ s           # => 3
/\d/ =~ s           # => nil