Unexpected behaviour

I tried the following in versions 1.8.* and 2.0.*. Output from console
given below.

--------------------------------------------

h = Hash.new([]) # Want default output to be a list

=> {}

h[‘a’] # I expect an empty list and I get it

=> []

h[‘a’].push(10) # Works as expected…

=> [10]

h[‘a’] # Ok… want to check if the key ‘a’ was set in the hash

=> [10]

h # This should not be an empty hash…Wow, what happened?

=> {}

h.has_key?(‘a’)

=> false

h[‘a’] = h[‘a’].push(100) # Ok, let me set things explicitly

=> [10, 100]

h # Is the following output expected?

=> {“a”=>[10, 100]}

---------------------------------------------

Note that h[‘a’] points to [10] even though the key ‘a’ does not exist
in the hash. More bizarre is when I set things explicitly, and push 100
to the list at the same time. Then the hash shows the key ‘a’ with [10,
100] as the value.

I understand why the key ‘a’ was not formed when I did h[‘a’].push(10).
What is inconsistent is that h[‘a’] kept pointing to [10] even though
h.has_key?(‘a’) is false

Is this an expected behavior? Can someone explain please.

Thanks

This is mentioned in the documentation of Hash.new:
http://www.ruby-doc.org/core-2.1.2/Hash.html#method-c-new

When you do this:

h = Hash.new([])

That Array is the same Array for every key.

If you want a different Array every time, you need to use a block:

h = Hash.new { |hash,key| hash[key] = [] }

Hi Joel, you are absolutely correct, but that was not the issue.

My confusion is that after I did h[‘a’].push(10), Ruby did as expected
and gave me [10]. Next, I printed h[‘a’] and it gave me [10], again all
good. Now, I check for existence of the key ‘a’ in the hash but it does
not exist, even though h[‘a’] gives me [10].

Maybe my issue is somehow related to your explanation, but I cannot see
it. Any thoughts?

Thanks.

Anirban Bh wrote in post #1153287:

My confusion is that after I did h[‘a’].push(10), Ruby did as expected
and gave me [10]. Next, I printed h[‘a’] and it gave me [10], again all
good. Now, I check for existence of the key ‘a’ in the hash but it does
not exist, even though h[‘a’] gives me [10].

The explanation is that Ruby has not created a key when you do h[‘a’],
but has just returned the default value for a nonexistent key. (h[‘a’]
is a get, h[‘a’]= is a set)

In more detail, when you do

h = Hash.new []
h[‘a’].push 10
[10]

Because h does not contain any keys, h[‘a’] returns the default value,
[], and pushes 10 onto it.

If you check the default value:

h.default
[10]

You can see there are no keys:

h.keys
[]
h
{}

If you ask for another non-existent key, you get back the same default
value:

h[‘b’]
[10]

To assign ‘a’ as a key, you need to do

h[‘a’] = []

And then things work as you expect:

h[‘a’].push 10
[10]
h.keys
[“a”]
h
=> {“a”=>[10]}

Hope this helps,

Peter.

Thank you Peter, you cleared my confusion when you said:

“If you ask for another non-existent key, you get back the same default
value”,

and the fact that it is not [] but [10] ties back to Joel’s explanation.

Thanks guys.