Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying the default hash value [duplicate]

Ruby lets you define default values for hashes:

h=Hash.new(['alright'])
h['meh'] # => ["alright"]

Assignment of a value shows up when displaying the hash, but a modified default does not. Where's 'bad'?

h['good']=['fine','dandy']
h['bad'].push('unhappy')
h # => {"good"=>["fine", "dandy"]}

'bad' shows up if we explicitly ask.

h['bad'] # => ["alright", "unhappy"]

Why does the modified default value not show up when displaying the hash?

like image 526
Dragon Avatar asked Feb 29 '12 02:02

Dragon


1 Answers

Hash's default value doesn't work like you're expecting it to. When you say h[k], the process goes like this:

  1. If we have a k key, return its value.
  2. If we have a default value for the Hash, return that default value.
  3. If we have a block for providing default values, execute the block and return its return value.

Note that (2) and (3) say nothing at all about inserting k into the Hash. The default value essentially turns h[k] into this:

h.has_key?(k) ? h[k] : the_default_value

So simply accessing a non-existant key and getting the default value back won't add the missing key to the Hash.

Furthermore, anything of the form:

Hash.new([ ... ])
# or
Hash.new({ ... })

is almost always a mistake as you'll be sharing exactly the same default Array or Hash for for all default values. For example, if you do this:

h = Hash.new(['a'])
h[:k].push('b')

Then h[:i], h[:j], ... will all return ['a', 'b'] and that's rarely what you want.

I think you're looking for the block form of the default value:

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

That will do two things:

  1. Accessing a non-existent key will add that key to the Hash and it will have the provided Array as its value.
  2. All of the default values will be distinct objects so altering one will not alter the rest.
like image 114
mu is too short Avatar answered Sep 21 '22 15:09

mu is too short