# Equality question

**URL:** <https://www.ruby-forum.com/t/equality-question/103630>\
**Category:** Ruby\
**Created:** [May 8, 2007, 5:33pm UTC](https://www.ruby-forum.com/t/equality-question/103630 "2007-05-08T17:33:54Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 8, 2007, 5:33pm UTC](https://www.ruby-forum.com/t/equality-question/103630/1 "2007-05-08T17:33:54Z")

</div>

I am trying to use complex values as hash keys (they are actually method  
calls caught by method\_missing). However strange things are happening.  
Can  
someone explain what’s happening here please where marked?

confs = {“default” =\> “! Config\nfoo=bar\n”}  
hash = {  
[:firmware\_id] =\> “12.4.8”,  
[:uptime] =\> 0,  
[:read\_configs] =\> confs,  
[:defuzz\_configs, confs] =\> {“default” =\> “foo=bar\n”},  
[:defuzz\_configs, {“conf”=\>“foo.txt”}] =\> {“default” =\>  
“foo=bar\n”},  
}  
p hash.size

key1 = [:defuzz\_configs, confs]  
p hash[key1] # this works

key2 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
p hash[key2] # this prints nil ?? \<\<\<\<\<\<\<\<\<\<\<

o1 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
o2 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
p o1 == o2 # prints true  
p o1.hash == o2.hash # prints false ?? \<\<\<\<\<\<\<\<\<\<\<

Thanks!

Brian.

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 8, 2007, 5:58pm UTC](https://www.ruby-forum.com/t/equality-question/103630/2 "2007-05-08T17:58:57Z")

</div>

Brian C. wrote:

> o1 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
> o2 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
> p o1 == o2 # prints true  
> p o1.hash == o2.hash # prints false ?? \<\<\<\<\<\<\<\<\<\<\<

That’s because the Hashs in o1 and o2 are two different objects.

> > hash={:bla=\>:blubb}  
> > =\> {:bla=\>:blubb}
> 
> > a1=[:a,hash]  
> > =\> [:a, {:bla=\>:blubb}]
> 
> > a2=[:a,hash]  
> > =\> [:a, {:bla=\>:blubb}]
> 
> > a3=[:a,{:bla=\>:blubb}]  
> > =\> [:a, {:bla=\>:blubb}]
> 
> > a1==a3  
> > =\> true
> 
> > a1.hash==a3.hash  
> > =\> false
> 
> > a1.hash==a2.hash  
> > =\> true
> 
> > hash[:blu]=:blo  
> > =\> :blo
> 
> > p a1,a2,a3  
> > [:a, {:bla=\>:blubb, :blu=\>:blo}]  
> > [:a, {:bla=\>:blubb, :blu=\>:blo}]  
> > [:a, {:bla=\>:blubb}]  
> > =\> nil
> 
> > a1==a3  
> > =\> false
> 
> > a1==a2  
> > =\> true

HTH,  
Sebastian H.

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 8, 2007, 6:56pm UTC](https://www.ruby-forum.com/t/equality-question/103630/3 "2007-05-08T18:56:16Z")

</div>

On Wed, May 09, 2007 at 12:58:01AM +0900, Sebastian H. wrote:

> Brian C. wrote:
> 
> > o1 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
> > o2 = [:defuzz\_configs, {“conf”=\>“foo.txt”}]  
> > p o1 == o2 # prints true  
> > p o1.hash == o2.hash # prints false ?? \<\<\<\<\<\<\<\<\<\<\<
> 
> That’s because the Hashs in o1 and o2 are two different objects.

So hashes and arrays don’t behave the same in this regard?

o1 = [“hello”, [“world”]]  
o2 = [“hello”, [“world”]]  
p o1 == o2  
p o1.hash == o2.hash # prints true

o1 = {“key”=\>“hello”}  
o2 = {“key”=\>“hello”}  
p o1 == o2  
p o1.hash == o2.hash # prints false

I wonder why this is?

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 9, 2007, 2:35am UTC](https://www.ruby-forum.com/t/equality-question/103630/4 "2007-05-09T02:35:18Z")

</div>

On May 9, 2007, at 1:55 AM, Brian C. wrote:

> I wonder why this is?

I’m a bit confused by this too. I’ve got seemingly conflicting stuff  
here:

irb(main):001:0\> h1 = [‘hi’, [‘dude’]]  
=\> [“hi”, [“dude”]]  
irb(main):002:0\> h2 = [‘hi’, [‘dude’]]  
=\> [“hi”, [“dude”]]  
irb(main):003:0\> h1.class  
=\> Array  
irb(main):004:0\> h2.class  
=\> Array  
irb(main):005:0\> h1 == h2  
=\> true  
irb(main):006:0\> h1[1] == h2[1]  
=\> true  
irb(main):007:0\> h3 = h2  
=\> [“hi”, [“dude”]]  
irb(main):009:0\> h2 == h3  
=\> true  
irb(main):010:0\> hash1 = {‘greet’ =\> ‘hi’}  
=\> {“greet”=\>“hi”}  
irb(main):011:0\> hash1.class  
=\> Hash  
irb(main):012:0\> hash2 = hash1  
=\> {“greet”=\>“hi”}  
irb(main):013:0\> hash1 == hash2  
=\> true  
irb(main):014:0\> hash1[1]  
=\> nil  
irb(main):016:0\> hash1.inspect  
=\> “{“greet”=\>“hi”}”  
irb(main):017:0\> hash1.class  
=\> Hash  
irb(main):019:0\> ‘greet’  
=\> “greet”  
irb(main):020:0\> hash1[‘greet’]  
=\> “hi”  
irb(main):025:0\> hash1[‘greet’] == hash2[‘greet’]  
=\> true  
irb(main):026:0\> p h1 == h2  
true  
=\> nil  
irb(main):027:0\> p hash1 == hash2  
true  
=\> nil  
irb(main):028:0\> p hash1  
{“greet”=\>“hi”}  
=\> nil  
irb(main):029:0\> p hash1.hash  
1773356  
=\> nil  
irb(main):030:0\> p hash1.to\_hash  
{“greet”=\>“hi”}  
=\> nil  
irb(main):031:0\> p hash2.hash  
1773356  
=\> nil  
irb(main):032:0\> hash1 == hash2  
=\> true  
irb(main):033:0\> hash1.hash == hash2.hash  
=\> true  
irb(main):034:0\> o1 = {“key” =\> “hi”}  
=\> {“key”=\>“hi”}  
irb(main):035:0\> o2 = {“key” =\> “hi”}  
=\> {“key”=\>“hi”}  
irb(main):037:0\> p o1 == o2  
true  
=\> nil  
irb(main):038:0\> o1.hash  
=\> 1844056  
irb(main):039:0\> o2.hash  
=\> 1830256  
irb(main):040:0\> o1 = {“name” =\> “bob”}  
=\> {“name”=\>“bob”}  
irb(main):041:0\> o2 = {“name” =\> “bob”}  
=\> {“name”=\>“bob”}  
irb(main):042:0\> o1 == o2  
=\> true  
irb(main):043:0\> o1.hash  
=\> 1769496  
irb(main):044:0\> o2.hash  
=\> 1757086  
irb(main):045:0\> h1.hash  
=\> -382289162  
irb(main):046:0\> h2.hash  
=\> -382289162  
irb(main):047:0\> hash1.hash  
=\> 1773356  
irb(main):048:0\> hash2.hash  
=\> 1773356  
irb(main):049:0\>

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 9, 2007, 2:59am UTC](https://www.ruby-forum.com/t/equality-question/103630/5 "2007-05-09T02:59:19Z")

</div>

On May 9, 2007, at 1:55 AM, Brian C. wrote:

> I wonder why this is?

it’s worth exploring further! (the ruby cookbook has a good section  
on ruby’s hashes)  
I made two hashes like yours.

irb(main):011:0\> o1. **id**  
=\> 1611054  
irb(main):012:0\> o2. **id**  
=\> 1586104  
irb(main):013:0\> o1.hash  
=\> 1611054  
irb(main):014:0\> o2.hash  
=\> 1586104

As you can see the two hashes don’t share the same object id, .hash  
method of objects creates a hash value for the object (confusing  
terminology, I know) but with hashes , that hash value just happens  
to be the same as the object id.  
They may contain (references to) the same objects, so that makes  
these two hashes look a lot alike, but they’re as different as you  
and your clone.

What’s more confusing? Try messing with symbols in your hashes. Then  
wrap your head around it.  
I finally got a handle on symbols. They’re like hard links in unix.  
little wormholes if you will.

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 9, 2007, 12:57pm UTC](https://www.ruby-forum.com/t/equality-question/103630/6 "2007-05-09T12:57:15Z")

</div>

On Wed, May 09, 2007 at 09:58:46AM +0900, John J. wrote:

> What’s more confusing? Try messing with symbols in your hashes. Then  
> wrap your head around it.  
> I finally got a handle on symbols. They’re like hard links in unix.  
> little wormholes if you will.

That I don’t have a problem with.

A symbol is basically an immutable string, which is also a singleton.

That is,

```
a = :foo
b = :foo
c = "foo".to_sym

```

will always return the exact same object for a, b and c.

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 9, 2007, 11:06am UTC](https://www.ruby-forum.com/t/equality-question/103630/7 "2007-05-09T11:06:01Z")

</div>

On 08.05.2007 18:55, Brian C. wrote:

> o1 = [“hello”, [“world”]]  
> o2 = [“hello”, [“world”]]  
> p o1 == o2  
> p o1.hash == o2.hash # prints true
> 
> o1 = {“key”=\>“hello”}  
> o2 = {“key”=\>“hello”}  
> p o1 == o2  
> p o1.hash == o2.hash # prints false
> 
> I wonder why this is?

Probably because Hashes store not only key value pairs but also default  
value and an optionally block that is invoked if an element is missing  
from the Hash. Now, blocks are difficult to compare in itself but the  
question here is: on what basis do you consider Hashes equivalent? Do  
you include the default object or not etc. As far as I remember this  
has been discussed on the list in the past to some extent. The solution  
is of course to use your own class for your keys. Since they seem to be  
pretty complex that’s a good idea anyway.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 9, 2007, 1:08pm UTC](https://www.ruby-forum.com/t/equality-question/103630/8 "2007-05-09T13:08:16Z")

</div>

On Wed, May 09, 2007 at 06:05:11PM +0900, Robert K. wrote:

> > I wonder why this is?
> 
> Probably because Hashes store not only key value pairs but also default  
> value and an optionally block that is invoked if an element is missing  
> from the Hash.

OK, then I’m missing some subtlety between hash1 == hash2 (which is  
true),  
and hash1.eql? hash2 (which is false).

But given just arrays, and arrays of arrays, array1 == array2 and  
array1.eql? array2 are both true. And so is array1.hash == array2.hash

So it appears that someone has decided that hashes cannot be used  
usefully  
as hash keys, but I cannot see why.

> The solution  
> is of course to use your own class for your keys. Since they seem to be  
> pretty complex that’s a good idea anyway.

I solved my problem by doing a linear search over the hash to find the  
entry, which seems silly, but it works.

```
# Was: return @output[input]
@output.each { |(k,v)| return v if k == input }

```

Making “my own class” was not an option. I was building a small mock  
object,  
and the hash key is whatever method\_missing receives. If the caller of  
the  
mock object passes in a hash, then a hash is what I get.

class Mock  
def self.prepare(output)  
@output = output  
end  
def self.[]=(input,output)  
@output[input] = output  
end  
def self.  
@output.each { |(k,v)| return v if k == input }  
raise “No response for #{input.inspect}”  
end

attr\_reader :actions  
def initialize(\*args)  
@actions = [[:initialize] + args]  
end  
def method\_missing(\*args)  
# STDERR.puts “#{args.inspect} =\> #{self.class[args].inspect}”  
@actions \<\< args  
self.class[args]  
end  
end

Mock.prepare({  
[:flurble] =\> ‘boo’,  
})

a = Mock.new(123)  
res = a.flurble  
p res  
p a.actions

Yes, I know there are other mock solutions out there. I would rather  
just  
write something which is (a) small, and (b) does exactly what I need.

Regards,

Brian.
