Hash.new with a block?

7

7stud --

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.
 
R

Robert Klemme

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
 
7

7stud --

Robert said:
$ 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.
 
A

Alex Gutteridge

Robert said:
$ 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.

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 Gutteridge

Bioinformatics Center
Kyoto University
 
7

7stud --

Alex said:
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
 
A

Alex Gutteridge

Alex said:
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

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 Gutteridge

Bioinformatics Center
Kyoto University
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,264
Messages
2,571,321
Members
48,005
Latest member
ChasityFan

Latest Threads

Top