# Being very confused about this hash

**URL:** <https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137>\
**Category:** Ruby\
**Created:** [January 6, 2010, 4:40am UTC](https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137 "2010-01-06T04:40:23Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [January 6, 2010, 4:40am UTC](https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137/1 "2010-01-06T04:40:23Z")

</div>

Hi,

irb(main):039:0\> hash = Hash.new []  
=\> {}  
irb(main):040:0\> hash[‘abc’] \<\< 3  
=\> [3]  
irb(main):041:0\> hash.keys  
=\> []  
irb(main):042:0\> hash[‘def’]  
=\> [3]

Since I have created a key/value pair with hash[‘abc’] \<\< 3, why  
hash.keys show nothing?  
And, why hash[‘abc’] \<\< 3 changed the hash’s default value (which  
should be an empty array)?

Thanks.

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [January 6, 2010, 5:02am UTC](https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137/2 "2010-01-06T05:02:38Z")

</div>

Ruby N. wrote:

> Since I have created a key/value pair with hash[‘abc’] \<\< 3, why  
> hash.keys show nothing?  
> And, why hash[‘abc’] \<\< 3 changed the hash’s default value (which  
> should be an empty array)?

I’m not sure why hash.keys was empty.

But with regard to the default value, we are providing an  
object (a specific instance of the Array class) to be used  
as the default.

We can illustrate this by asking Ruby to show us the object\_id  
of the default object:

irb(main):001:0\> ary = []  
=\> []  
irb(main):002:0\> ary.object\_id  
=\> 20919800  
irb(main):003:0\> h = Hash.new ary  
=\> {}  
irb(main):004:0\> h[‘foo’].object\_id  
=\> 20919800  
irb(main):005:0\> h[‘bar’].object\_id  
=\> 20919800

So we can see the object\_id of the default object is indeed  
the same object\_id of the array we provided to Hash.new.

* * *

We can instead provide a block to Hash.new which allows us  
to create a _new_ unique object (instance of Array) whenever  
a new default value is needed:

irb(main):001:0\> h = Hash.new {|h,k| h[k] = []}  
=\> {}  
irb(main):002:0\> h[‘abc’] \<\< 3  
=\> [3]  
irb(main):003:0\> h.keys  
=\> [“abc”]  
irb(main):004:0\> h[‘def’]  
=\> []

Regards,

Bill

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [January 6, 2010, 6:53am UTC](https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137/3 "2010-01-06T06:53:16Z")

</div>

On Tuesday 05 January 2010 09:39:53 pm Ruby N. wrote:

> irb(main):039:0\> hash = Hash.new []

I assume here that [] is the default value, right?

> hash.keys show nothing?  
> Because you haven’t set anything in the hash. That is,

hash[‘abc’] = 3

is equivalent to:

hash.[]=(‘abc’, 3)

On the other hand, what you’ve done is:

hash[‘abc’] \<\< 3

That’s equivalent to:

hash. \<\< 3

I don’t know if that helps, but that’s the difference. Let me put it  
this way  
– suppose you hadn’t changed the default value:

irb(main):001:0\> hash = {}  
=\> {}  
irb(main):002:0\> hash[‘abc’]  
=\> nil  
irb(main):003:0\> hash.keys  
=\> []

Do you understand why that works the way it does? But there’s nothing  
special  
about nil here, it’s just the, erm, _default_ default value – it’s what  
Hash  
uses as a default value if you don’t specify one.

> And, why hash[‘abc’] \<\< 3 changed the hash’s default value (which  
> should be an empty array)?

Because you set the default value to [], which creates an empty array  
object,  
once. The hash is just assigning it each time. Think of it this way:

irb(main):004:0\> default = []  
=\> []  
irb(main):005:0\> a = default  
=\> []  
irb(main):006:0\> b = default  
=\> []  
irb(main):007:0\> a \<\< 3  
=\> [3]  
irb(main):008:0\> b  
=\> [3]

What you really want is the block notation of creating a hash, which  
lets you  
actually specify some code that’s run to create a default value, as Bill  
Kelly  
says. The reason his code works is that when you try to access a value  
that  
doesn’t exist, it actually runs some code which sets that value:

h = Hash.new {|h,k| h[k] = []}

It wouldn’t work at all if you just did this:

h = Hash.new {|h,k| []}

That would at least give you a new array each time, but since it  
wouldn’t set  
it, you’d see weird things:

irb(main):010:0\> h[‘abc’] \<\< 3  
=\> [3]  
irb(main):011:0\> h[‘abc’]  
=\> []  
irb(main):012:0\> h.keys  
=\> []

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [January 6, 2010, 7:10am UTC](https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137/4 "2010-01-06T07:10:14Z")

</div>

On Wed, Jan 6, 2010 at 1:52 PM, David M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> hash.[]=(‘abc’, 3)
> 
> On the other hand, what you’ve done is:
> 
> hash[‘abc’] \<\< 3
> 
> That’s equivalent to:
> 
> hash. \<\< 3

Thanks for the explaining, now I think I have got it.  
I’m always thinking it as the Perl way, since in Perl the syntax like  
hash[‘abc’] \<\< 3 will create a key/value pairs.

perl -MData::Dumper -le ‘$hash={}; push @{$hash-\>{‘abc’}},3; print  
Dumper $hash’  
$VAR1 = {  
‘abc’ =\> [  
3  
]  
};

I didn’t know in Ruby hash[‘abc’] = 3 and hash[‘abc’] \<\< 3 are  
different.  
Thanks again.

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [January 6, 2010, 6:56am UTC](https://www.ruby-forum.com/t/being-very-confused-about-this-hash/181137/5 "2010-01-06T06:56:11Z")

</div>

I believe that keys is returning empty because the hash is empty. If  
I remember correctly, the default hash element mechanism doesn’t  
create the element, just returns the default element when referenced.

So hash[‘abc’] returns our specific default instance which then gets a  
3 added to it. That’s why all future defaults get the [3]…its the  
identical instance. But no actually elements are added to the hash.
