Equality and sameness in Ruby

June 29, 2009 Pivotal Labs

Let’s say you are building a leetspeak that deals with w00ts. You might write a class that looks like this:

class Woot
  def ==(other)
    true
  end
end

In theory, any Woot is equal to anything else:

puts Woot.new == Woot.new # true

You might think that with this setup, you could do something like this:

x = [ Woot.new ]
y = [ Woot.new ]
z = x - y

You might expect z to be an empty array in the case, but oh how wrong you would be. In the example above, the == is never called at all.

After reading through the docs on Array, overriding all 4 equals method in ruby (eql?, equal?, ==, ===) and overriding object_id you will still not be able to make it work.

A quick look through the C code shows that Array#- hashifies the array. The hashing algorithm looks for a method called “hash” on the object. If that’s not there, it uses the memory id. Great, so now we can just add hash and be done, like this:

class Woot
  def ==(other)
    true
  end

  def hash
    1
  end
end

Wrong! You still don’t get an empty array. It turns out that the hash algorithm calls eql?, not ==, so you have to make sure to alias that as well, like so:

class Woot
  def ==(other)
    true
  end
  alias :eql? :==

  def hash
    1
  end
end

So if you want normal array semantics for your objects, be sure to provide #hash, #== and #eql?.

About the Author

Biography

Previous
Ideas as Motivation
Ideas as Motivation

It's hard for me to be excited about participating when I feel like I can't contribute ideas. Sometimes it ...

Next
Automated Configuration @ Velocity 2009
Automated Configuration @ Velocity 2009

Theo Schlossnagle: "I don't care what you use: puppet, chef, bcfg2, cfengine - choose one and automate your...

×

Subscribe to our Newsletter

!
Thank you!
Error - something went wrong!