# TIL: Hash Edition

> Last updated: 2015-03-13

I was reviewing some code for a co-worker today and learned something
new about `Hash`. My co-worker was using a ruby hash not as a
dictionary but as a O(1) look up collection (also known as a hash
table). Because of this there were a few places in his code that
looked something like this:

```ruby
h = {}

def add_the_keys(keys_to_add)
  keys_to_add.each do |k|
    h[k] = 0
  end
end
```

Whenever I see the same value being used for all the keys in a hash I
think "use a hash with a default value". I dutiful rewrote the code to
look this like:

```ruby
h = Hash.new(0)

def add_the_keys(keys_to_add)
  keys_to_add.each do |k|
    h[k]
  end
end
```

And then the tests started failing. Out of curiousity I tried this instead:

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

def add_the_keys(keys_to_add)
  keys_to_add.each do |k|
    h[k]
  end
end
```

And the tests passed again. What the heck? So I went into irb and
  tried a couple things:
kxx
```ruby
h1 = {}

h1[:a] = 0    # 0
h2[:b]        # nil

h1.keys       # [:a]

h2 = Hash.new(0)

h2[:a] = 0    # 0
h2[:b]        # 0

h2.keys       # [:a]

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

h3[:a] = 0    # 0
h3[:b]        # 0

h3.keys       # [:a, :b]
```

Moral of the story: Keys are not added to a hash unless there is an
assigment or there is a default_proc. Also, if you want a collection
with O(1 ) key access use `Set`. It is a hash under the hood but using
`Set` reveals your intent.

P.S. For extra fun try this:

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

h4[:a] = 0    # 0
h4[:b]        # hang
```
