1

I want to understand why a in the following is an empty hash after a[:a] is called, which is not empty:

a = Hash.new({a:1}) # => {}
a[:a][:a] += 1      # => 2
a                   # => {}
a[:a]               # => {:a=>2}

I know that {a: 1} is shared between every inexistent key (a[:something_inexistent]). But why isn't it displayed as a key of a? If possible, using Ruby's internal would be much appreciated.

sawa
  • 165,429
  • 45
  • 277
  • 381
waldyr.ar
  • 14,424
  • 6
  • 33
  • 64
  • 1
    `{a:1}` is the default *value*, so if `a` does not have a key `k`, `a[k]` returns `{a:1}` but it doesn't change the hash. If you want to change the hash, `a[:k] = a[:k]; a #=> {:k=>{:a=>1}}`. `h` would be a better choice than `a` for a variable whose value is a hash, just like `a` would be better than `h` for an array. – Cary Swoveland Oct 08 '15 at 01:34
  • I saw a post recently, which might help: [Bottomless Ruby Hash](http://firedev.com/posts/2015/bottomless-ruby-hash/) – ShallmentMo Oct 08 '15 at 02:54

1 Answers1

5

It is because a[:a] is never assigned. When you do a[:a], it is not returning the stored value, but is returning the default value.

Unlike this, when you instead have:

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

then, whenever a missing key is called, the block is executed, which assigns the value to the key, and a will no longer be an empty hash.

sawa
  • 165,429
  • 45
  • 277
  • 381
  • Why does passing an argument of `{a:1}` to `Hash.new` set the default value to be one, though? That seems kind of weird. – Rob Wise Oct 08 '15 at 01:34
  • I think part of his confusion is that `a = Hash.new({a:1})` is not the same as `a = {a: 1}`. I know that got me when I first looked at it. – Beartech Oct 08 '15 at 01:35
  • Ahh, I think I understand now from looking at [the API](http://docs.ruby-lang.org/en/2.2.0/Hash.html#method-c-new). See how they pass in "Go Fish" as the argument, and then call `h["c"]` and get "Go Fish" back out? He set the default value for when the key doesn't exist to be another, inner hash `{a:1}`. When he did the `+= 1` command, he actually was changing what the default value was, now made to be `{a:2}`, but never assigned it to any keys so the main hash is still empty. – Rob Wise Oct 08 '15 at 01:37
  • 1
    That's exactly what sawa answered. Nice answer I hope others make through as I did :) – waldyr.ar Oct 08 '15 at 01:38
  • 1
    Yes I know, that's why I upvoted it and didn't make my own answer. – Rob Wise Oct 08 '15 at 01:39
  • 1
    In case it isn't clear, the default value is {a:1}, not 1. – Brian Oct 08 '15 at 01:42