Code & Clay – Notes to self. Mainly Ruby/Rails.

Override `#hash` when overriding `#eql?`

In my notes here, I’ve written that #hash must be overridden when overriding #eql?. I was unsure why this was the case.

What is #hash?

I see in pry that all objects respond to #hash:

> 1.hash
=> 3748939910403886956
> 'a'.hash
=> 1677925148165319732
> [1,2,3].hash
=> -2230614089907012012
=> -2249667312364590389

Equal objects return the same value:

> 1 == 1
=> true
> 1.hash
=> 3748939910403886956
> 1.hash
=> 3748939910403886956

Hash comes from the Kernel module:

> 1.method(:hash).owner
=> Kernel

The Kernel module is included by class Object, so its methods are available in every Ruby object.

It’s basically a bunch of helper methods made available to every class.

Kernel#hash seems to be undocumented though. It’s not in in the docs for the Kernel module. Though, that page does point towards the Object class page for information on Kernel instance methods. But there’s nothing on it there either.

The explanation to why #hash needs to be overridden when #eql is changed is in the Hash docs.

Two objects refer to the same hash key when their hash value is identical and the two objects are eql? to each other.

Two objects can have the same hash value but be unequal however this would be detriment to the speed of the hash.

So when keying by multiple objects, so long as their hash and eql? values match, they will point to the same bucket.

If you really want to get to grips with Ruby development and gain a solid understanding of Object Oriented Design, I thoroughly recommend Sandi Metz's Practical Object Oriented Design in Ruby. It's the perfect introduction to OOP and pragmatic Ruby. You can buy it here.

“Meticulously pragmatic and exquisitely articulate, Practical Object Oriented Design in Ruby makes otherwise elusive knowledge available to an audience which desperately needs it. The prescriptions are appropriate both as rules for novices and as guidelines for experienced professionals.”

Katrina Owen, Creator, Exercism

Essential Reading: Learn Rails 6