Hash.new(confusion)

(7rans) #1

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

T.

(Joel VanderWerf) #2

Trans wrote:

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

T.

Try

p r.default

and you'll see what's going on.

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

(Gennady) #3

If you specify a parameter for Hash.new the SAME object will be used for any default value (see documentation). If you modify it, it will be modified for all default values afterwards. Try to see what the value will be returned for r[:a] if you do it again. I bet it will be {:c => 10}. As well as for r[:c], r[10] and so on.

Gennady.

···

On Aug 28, 2005, at 21:16, Trans wrote:

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

T.

(Mitch) #4

r is independent of r[:b]. r[:b] is a hash with a value containing another hash/key value.

ie {:b => {:c => 10}} NOT {:b => 10, :c = 10}. If I understand your confusion correctly.

irb(main):001:0> def r
irb(main):002:1> @r ||= Hash.new({})
irb(main):003:1> end
=> nil
irb(main):004:0> r[:a]
=> {}
irb(main):005:0> r.empty?
=> true
irb(main):006:0> r[:a] = 1
=> 1
irb(main):007:0> r.empty?
=> false
irb(main):008:0> r[:b][:c] = 10
=> 10
irb(main):009:0> r
=> {:a=>1}
irb(main):010:0> r[:b]
=> {:c=>10}
irb(main):011:0> (r[:b])[:c]
=> 10
irb(main):012:0> r[:a]
=> 1
irb(main):013:0> r.size
=> 1
irb(main):014:0> r[:b].size
=> 1
irb(main):015:0> r[:b][:d] = 300000
=> 300000
irb(main):016:0> r[:b].size
=> 2
irb(main):018:0> r
=> {:a=>1}
irb(main):019:0> r[:b]
=> {:d=>300000, :c=>10}

Or did I completely miss your point?

Mitch

···

On Aug 28, 2005, at 11:16 PM, Trans wrote:

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

T.

(Dave Burt) #5

transfire@gmail.com wrote:

...
Please explain how r is empty but r[:b] exists. Thank You.

# To summarize:
h = Hash.new({})
h[1][2] = 3
h #=> {}
h.default #=> {2=>3}

So you've added to the default object. It might be helpful to note another
wrong way to do this:
h = Hash.new { {} }
h[1][2] = 3
h #=> {}
h.default #=> {}

Different, because default now returns a new hash every time.

But, to answer the implied question, "what is the code that will do what I
intend?" there are a few ways to do this:

# Just one level of magic new hashes
h = Hash.new {|hash, key| hash[key] = {} }
h[1][2] = 3
h #=> {1=>{2=>3}}
h[1][2][3] = 4 # Error (calling []= on nil)

# Auto-vivifying hash: using proc
auto_vivivy_hash = proc {|hash, key| hash[key] = Hash.new
&auto_vivivy_hash }
h = Hash.new &auto_vivify_hash
h[1][2][3] = 4 #=> {1=>{2=>{3=>4}}}

# Auto-vivifying hash: using Hash subclass
class X < Hash
  def default(key = nil)
    self[key] = self.class.new
  end
end
h = X.new #=> {}
h[1][2][3] = 4
h #=> {1=>{2=>{3=>4}}}

Cheers,
Dave

(David A. Black) #6

Hi --

···

On Mon, 29 Aug 2005, Trans wrote:

irb(main):006:0> def r
irb(main):007:1> @r ||= Hash.new({})
irb(main):008:1> end
=> nil
irb(main):009:0> r[:a]
=> {}
irb(main):010:0> r[:b][:c] = 10
=> 10
irb(main):011:0> r
=> {}
irb(main):012:0> r[:b]
=> {:c=>10}
irb(main):013:0>

Please explain how r is empty but r[:b] exists. Thank You.

r[:b] doesn't exist, so instead, you get the hash's default value
(which is what is returned for non-existent keys).

David

--
David A. Black
dblack@wobblini.net

(7rans) #7

Ahhhh, Now I _finally_understand. It's quite subtle.

Thank You All!

T.