Hash.new with a block?

Hi,

In the code:

h = Hash.new {|hash, key| hash[key] = []}

what method is yielding the values hash, key to the code block? It
doesn’t seem like it could be new() since new() isn’t called when you
lookup a key in a hash. Does new() somehow associate that block with
the method [] in Hash?

Thanks.

On 03.09.2007 06:50, 7stud – wrote:

In the code:

h = Hash.new {|hash, key| hash[key] = []}

what method is yielding the values hash, key to the code block? It
doesn’t seem like it could be new() since new() isn’t called when you
lookup a key in a hash. Does new() somehow associate that block with
the method [] in Hash?

$ ruby -e ‘h=Hash.new {|h,k| h[k]=[]}; set_trace_func(lambda {|*a| p
a}); h[1]<<2’
[“line”, “-e”, 1, nil, #Binding:0x1002fdf4, false]
[“c-call”, “-e”, 1, :[], #Binding:0x1002fdb8, Hash]
[“c-call”, “-e”, 1, :default, #Binding:0x1002fca0, Hash]
[“c-call”, “-e”, 1, :call, #Binding:0x1002fb9c, Proc]
[“line”, “-e”, 1, nil, #Binding:0x1002f9a8, false]
[“c-call”, “-e”, 1, :[]=, #Binding:0x1002f8a4, Hash]
[“c-return”, “-e”, 1, :[]=, #Binding:0x1002f868, Hash]
[“c-return”, “-e”, 1, :call, #Binding:0x1002f778, Proc]
[“c-return”, “-e”, 1, :default, #Binding:0x1002f688, Hash]
[“c-return”, “-e”, 1, :[], #Binding:0x1002f598, Hash]
[“c-call”, “-e”, 1, :<<, #Binding:0x1002f4a8, Array]
[“c-return”, “-e”, 1, :<<, #Binding:0x1002f3b8, Array]

I believe there’s also some explanation in the documentation.

Kind regards

robert

Robert K. wrote:

$ ruby -e ‘h=Hash.new {|h,k| h[k]=[]}; set_trace_func(lambda {|*a| p
a}); h[1]<<2’
[“line”, “-e”, 1, nil, #Binding:0x1002fdf4, false]
[“c-call”, “-e”, 1, :[], #Binding:0x1002fdb8, Hash]
[“c-call”, “-e”, 1, :default, #Binding:0x1002fca0, Hash]
[“c-call”, “-e”, 1, :call, #Binding:0x1002fb9c, Proc]
[“line”, “-e”, 1, nil, #Binding:0x1002f9a8, false]
[“c-call”, “-e”, 1, :[]=, #Binding:0x1002f8a4, Hash]
[“c-return”, “-e”, 1, :[]=, #Binding:0x1002f868, Hash]
[“c-return”, “-e”, 1, :call, #Binding:0x1002f778, Proc]
[“c-return”, “-e”, 1, :default, #Binding:0x1002f688, Hash]
[“c-return”, “-e”, 1, :[], #Binding:0x1002f598, Hash]
[“c-call”, “-e”, 1, :<<, #Binding:0x1002f4a8, Array]
[“c-return”, “-e”, 1, :<<, #Binding:0x1002f3b8, Array]

I believe there’s also some explanation in the documentation.

I don’t know what that output means. I have also looked up Hash.new in
the book “Programming Ruby (2nd ed)” and it doesn’t mention anything
about the particulars. The same documentation is displayed when I type:

$ri Hash.new
…If a block is specified, it will be called with the hash object
and the key, and
should return the default value. It is the block’s responsibility
to store the value in the hash if required.

So, as far as I can tell, the Ruby documentation doesn’t help with my
question.

On 3 Sep 2007, at 15:31, 7stud – wrote:

[“c-return”, “-e”, 1, :call, #Binding:0x1002f778, Proc]
[“c-return”, “-e”, 1, :default, #Binding:0x1002f688, Hash]
[“c-return”, “-e”, 1, :[], #Binding:0x1002f598, Hash]
[“c-call”, “-e”, 1, :<<, #Binding:0x1002f4a8, Array]
[“c-return”, “-e”, 1, :<<, #Binding:0x1002f3b8, Array]

I believe there’s also some explanation in the documentation.

I don’t know what that output means.

Each line shows an ‘event’ occurring in the script. Where event is
calling a C method, returning, etc… (see Kernel#set_trace_func). We
can summarise what’s going on:

[“line”, “-e”, 1, nil, #Binding:0x1002fdf4, false]

Process new line.

[“c-call”, “-e”, 1, :[], #Binding:0x1002fdb8, Hash]

Call the C method Hash#[]

[“c-call”, “-e”, 1, :default, #Binding:0x1002fca0, Hash]

Call the C method Hash#default.

[“c-call”, “-e”, 1, :call, #Binding:0x1002fb9c, Proc]

Call the C method Proc#call. This Proc is the one given to Hash.new I
guess. Here is the answer to your original question.

[“line”, “-e”, 1, nil, #Binding:0x1002f9a8, false]

I guess this means we’ve moved into the Proc

[“c-call”, “-e”, 1, :[]=, #Binding:0x1002f8a4, Hash]

We call Hash#[] inside our Proc

[“c-return”, “-e”, 1, :[]=, #Binding:0x1002f868, Hash]
[“c-return”, “-e”, 1, :call, #Binding:0x1002f778, Proc]
[“c-return”, “-e”, 1, :default, #Binding:0x1002f688, Hash]
[“c-return”, “-e”, 1, :[], #Binding:0x1002f598, Hash]

Return from each of the previous calls.

[“c-call”, “-e”, 1, :<<, #Binding:0x1002f4a8, Array]
[“c-return”, “-e”, 1, :<<, #Binding:0x1002f3b8, Array]

Push something onto the Array.

So short answer: Hash#[] calls Hash#default which in the case of Hash
objects with an associated Proc calls the Proc.

Alex G.

Bioinformatics Center
Kyoto University

Alex G. wrote:

So short answer: Hash#[] calls Hash#default which in the case of Hash
objects with an associated Proc calls the Proc.

Thanks for the explanation. So, is correct to assume that in the source
code for Hash#default there is a line somewhere that says something
like:

yield hash, key

On 3 Sep 2007, at 16:21, 7stud – wrote:

yield hash, key
Well proc.call(hash,key) really, which is almost (sort of) the same
thing! Here is the source code from hash.c with my comments:

static VALUE rb_hash_default(argc, argv, hash){
VALUE key;

 rb_scan_args(argc, argv, "01", &key);
 if (FL_TEST(hash, HASH_PROC_DEFAULT)) { //Test if default Proc

is present
if (argc == 0) return Qnil;
return rb_funcall(RHASH(hash)->ifnone, id_call, 2, hash,
key); //If so call the procs ‘call’ method
}
//with ‘hash’ and ‘key’ as args
return RHASH(hash)->ifnone;
}

Alex G.

Bioinformatics Center
Kyoto University