Guaranteed way to compare objects by identity in Ruby

Use BasicObject#equal?. According to Ruby documentation:

Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).

Need stronger guarantee? AFAIK can't receive it, BaseObject#object_id, ObjectSpace._id2ref, Hash#compare_by_identity can be overriden or monkey patched too (at least this is my personal belief).


The answer by mu is too short is great, but there is another way you can do it using a special feature of the Hash class:

def compare_by_identity(x, y)
  h = {}.compare_by_identity
  h[x] = 1
  h[y] = 2
  h.keys.size == 1
end

The compare_by_identity feature was added in Ruby 1.9.2, so this function won't work in earlier versions. I think mu is too short's answer is better.


You could grab an unbound version of Object#object_id, bind it to the object in question, and see what it says. Given your F class with one addition:

class F
  # ...
  def inspect; 'pancakes!' end # Just so we can tell what we have later.
end

Then:

>> f = F.new
>> f.object_id
=> pancakes!
>> unbound_object_id = Object.instance_method(:object_id)
>> unbound_object_id.bind(f).call
=> 2153000340
>> ObjectSpace._id2ref(2153000340).inspect
=> "pancakes!"

Of course, if someone opens up Object and replaces object_id then you're out of luck but this will be the least of your problems if someone does that. If you can grab your unbound_object_id UnboundMethod before anything else is loaded, then it won't matter if someone changes Object#object_id as your unbound_object_id will still be the original correct one.

So this round-about hack gives you a reliable object_id for any object (subject to the caveats above). Now you can grab and compare the object ids to get your reliable comparison.

Tags:

Ruby

Compare