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.
--
Posted via http://www.ruby-forum.com/.
$ 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
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.
> Robert Klemme 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.
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
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
> Alex Gutteridge 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
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;