0

Please follow the below code :

Part-I

> h = { "a" => 100, "b" => 200 }
=> {"a"=>100, "b"=>200}
> h.default = "Go fish"
=> "Go fish"
> h["a"]
=> 100
> h["z"]
=> "Go fish"
> h.default = proc do |hash, key|
*   hash[key] = key + key
> end
=> #<Proc:0x208bee8@(irb):5>
> h[2]
=> #<Proc:0x208bee8@(irb):5>
> h["cat"]
=> #<Proc:0x208bee8@(irb):5>

Part-II

> h = { "a" => 100, "b" => 200 }
=> {"a"=>100, "b"=>200}
> h.default_proc = proc do |hash, key|
*   hash[key] = key + key
> end
=> #<Proc:0x1e21df8@(irb):2>
> h[2]
=> 4
> h["cat"]
=> "catcat"

Now I am surprised to see, why h[2] and h["cat"] giving different output for the two codes in part-I and part-II.

Could you anyone please explain?

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
  • There's no surprise for me. `default` set the static default object(as you can see, the objectId is the same), while `default_proc` is something to be eval-ed. – halfelf Jan 13 '13 at 14:24
  • @halfelf i didn't get your point! a bit explanation in more details would be much appreciated! – Arup Rakshit Jan 13 '13 at 14:42

2 Answers2

2

Why? (Philosophical)

What if you wanted a hash of Procs? You can't just set the default value to be a Proc to run, because there wouldn't be a (trivial) mechanism to distinguish it from a Proc to return.

Maps of Procs might be used to implement a simple state machine or external DSL.

Why? (Technical)

Because that's the way [] is written:

VALUE
rb_hash_aref(VALUE hash, VALUE key)
{
    st_data_t val;

    if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
        if (!FL_TEST(hash, HASH_PROC_DEFAULT) &&
            rb_method_basic_definition_p(CLASS_OF(hash), id_default)) {
            return RHASH_IFNONE(hash);
        }
        else {
            return rb_funcall(hash, id_default, 1, key);
        }
    }
    return (VALUE)val;
}

As the docs to default say:

It is not possible to set the default to a Proc that will be executed on each key lookup.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
2
  • Hash#default= sets the value to be returned in case there is no such key. You set that to a proc in Part-I, and that is what you see being returned.
  • Hash#default_proc= sets the proc to be called on itself and the key in case there is no such key. If you do hash[2] = 2 + 2, then hash[2] will return 4. If you do hash["cat"] = "cat" + "cat", then hash["cat"] will return "catcat".
sawa
  • 165,429
  • 45
  • 277
  • 381
  • Perfect explanation! `+1` to you! – Arup Rakshit Jan 13 '13 at 14:38
  • Could you please say what to be used in what situation? means any real time programming example where i have to set the `part-I` settings for defaulting and one areas where i have to chose `part-II` settings? – Arup Rakshit Jan 13 '13 at 14:50
  • @VBSlover Maps of procs are an easy way to associated functionality with keys, for example, a simple state machine or external DSL. – Dave Newton Jan 13 '13 at 15:05
  • When you want the default to be a constant, for example the same `:foo` to whatever key, then you can use `default=`. If you want it to vary depending on the key, then you need to use `default_proc=`. – sawa Jan 13 '13 at 15:07
  • @sawa if you don't mind can you show me a tiny code against your statement,which might be better to understand! please :) – Arup Rakshit Jan 13 '13 at 15:45