Is it safe to override #hash and #eql? to enable hash key equality?

J

James

Hi,

I would like to use object instances as hash keys where two objects
containing the same datum both have the same key value. This does not
work by default (as expected given that these are two different
instances):

class Foo
def initialize(datum)
@datum = datum
end
end

# Two hash keys for the same datum
a = {Foo.new:)baz) => 1, Foo.new:)baz) => 2}
p a

# => {#<Foo:0x2a95e68888 @datum=:baz>=>1, #<Foo:0x2a95e68860
@datum=:baz>=>2}

However, this functionality can be obtained by overriding Object#hash
and Object#eql?:

class Bar

attr_reader :datum

def initialize(datum)
@datum = datum
end

def hash
@datum.hash
end

def eql?(other)
@datum.eql? other.datum
end

end

# One hash key for the same datum
b = {Bar.new:)baz) => 1, Bar.new:)baz) => 2}
p b

#=> {#<Bar:0x2a95e684f0 @datum=:baz>=>2}

My simple question is if this is safe/normal/OK for my intentions.
Based on perusal of the online Ruby documentation it looks like #eql?
has been overridden in a number of sub-classes for the same purpose.
But I wanted to get feedback from the community - has anyone here
tried this? Are there any known side-effects?

Thanks,
-James
 
R

Robert Klemme

Hi,

I would like to use object instances as hash keys where two objects
containing the same datum both have the same key value. This does not
work by default (as expected given that these are two different
instances):

class Foo
def initialize(datum)
@datum = datum
end
end

# Two hash keys for the same datum
a = {Foo.new:)baz) => 1, Foo.new:)baz) => 2}
p a

# => {#<Foo:0x2a95e68888 @datum=:baz>=>1, #<Foo:0x2a95e68860
@datum=:baz>=>2}

However, this functionality can be obtained by overriding Object#hash
and Object#eql?:

class Bar

attr_reader :datum

def initialize(datum)
@datum = datum
end

def hash
@datum.hash
end

def eql?(other)
@datum.eql? other.datum
end

end

# One hash key for the same datum
b = {Bar.new:)baz) => 1, Bar.new:)baz) => 2}
p b

#=> {#<Bar:0x2a95e684f0 @datum=:baz>=>2}

My simple question is if this is safe/normal/OK for my intentions.

Not only that: this is exactly how one should do it.
Based on perusal of the online Ruby documentation it looks like #eql?
has been overridden in a number of sub-classes for the same purpose.
But I wanted to get feedback from the community - has anyone here
tried this? Are there any known side-effects?

No, your use is absolutely correct. This is what this methods are meant
for. The only thing to remark is this: you can save yourself a lot
typing by doing:

Bar = Struct.new :datum

If you need additional methods in that class you can even do

Bar = Struct.new :datum do
def another_method
123
end
end

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top