I started this post in October 2013 (!) but never finished it. But it seems like something other folks might find interesting, so, here goes.
I was fiddling with Tracepoint
and I could see an event for Array#select
:
Incidentally, did you know that calling Array#select
without a block returns an Enumerator
?
I didn't. Anyhow, a TracePoint
event doesn't get fired for #size
or #length
, but one does for #count
:
And send(:length)
triggers one:
Seems weird, since #length
is a C function for which #size
is an alias:
So why doesn't a plain old #size
or #length
invocation result in a tracepoint event? I asked Pat Shaughnessy about it on the twitters and he pointed out that it's because size
is implemented - wait for it - as a YARV instruction! Sure enough, in insns.def
, there's opt_size
, and if I add a printf('heyo\n');
to the part of that definition that's handling arrays (via RBASIC_CLASS(recv) == rb_cArray
) and run ruby -e "[].size"
, there appears a flurry of heyos.
Kashap Kondamudi does a fine job of explaining the Ruby execution process so I won't repeat all that here. The short version, though, is that disassembling a size
method invocation shows that it's using a specialized opt_size
instruction:
whereas disassembling a select
invocation shows that it's using a more general instruction:
and the implementation for opt_send_without_block
presumably is also firing tracepoint events. I poked around a bit and it seems like that instruction uses the CALL_METHOD
macro which looks up the appropriate method and invokes it. That's not a great explanation because I didn't follow the flow there; maybe someone on the internet will fill in the missing pieces for me here.
Anyhow, takeaway is that Pat is a smart fella and everyone should buy a second copy of Ruby Under a Microscope, and also that when digging around in stuff like this, don't forget about the YARV instruction definitions!