Hello! As you know, in Ruby, a block is not an object for some reasons, one of which is performance. def f yield end def g &blk blk.call end In g, a block is explicitly converted to a Proc object. What about in f? Is a block still converted to a Proc object implicitly? If it's not converted, I understand the performance issue. However, it's always converted to a Proc object, I don't understand why blocks improve performance just because they are not objects. Can somebody explain this, please? Thanks. Sam
on 29.06.2006 19:57
on 29.06.2006 20:06
Hi,
In message "Re: Is a block converted to a Proc object before yield?"
on Fri, 30 Jun 2006 02:57:32 +0900, Sam Kong <sam.s.kong@gmail.com>
writes:
|Is a block still converted to a Proc object implicitly?
Not under the current implementation.
matz.
on 29.06.2006 20:20
Yukihiro Matsumoto wrote: > |Is a block still converted to a Proc object implicitly? > > Not under the current implementation. > > matz. I'm pretty sure that this is a very official answer...:-) Matz, I want to take this opportunity to thank you for making me a happy programmer with Ruby. Sam
on 29.06.2006 20:28
Sam Kong wrote: > blk.call > Can somebody explain this, please? You've got the answer already, but it's interesting to see how much of a difference it makes: (YMMV, of course.) require 'benchmark' def outer11(&bl) inner1(&bl) end def outer12(&bl) inner2(&bl) end def outer21 inner1 {yield} end def outer22 inner2 {yield} end def inner1(&bl) bl.call end def inner2 yield end n = 100000 Benchmark.bmbm(10) do |rpt| rpt.report("outer11") do n.times {outer11{}} end rpt.report("outer12") do n.times {outer12{}} end rpt.report("outer21") do n.times {outer21{}} end rpt.report("outer22") do n.times {outer22{}} end end __END__ Output: Rehearsal --------------------------------------------- outer11 0.890000 0.010000 0.900000 ( 0.894500) outer12 0.370000 0.000000 0.370000 ( 0.364880) outer21 0.770000 0.000000 0.770000 ( 0.776638) outer22 0.170000 0.000000 0.170000 ( 0.163393) ------------------------------------ total: 2.210000sec user system total real outer11 0.490000 0.000000 0.490000 ( 0.491969) outer12 0.400000 0.000000 0.400000 ( 0.396264) outer21 0.760000 0.000000 0.760000 ( 0.764508) outer22 0.160000 0.000000 0.160000 ( 0.161982)
on 29.06.2006 22:24
Joel VanderWerf wrote: > Sam Kong wrote: >> blk.call >> Can somebody explain this, please? > You've got the answer already, but it's interesting to see how much of a > difference it makes: (YMMV, of course.) Thank you for the benchmark which convinces me of blocks being more efficient. What a lovely community Ruby has! Sam
on 30.06.2006 14:56
Joel VanderWerf wrote: > Sam Kong wrote: > > Hello! > > > > As you know, in Ruby, a block is not an object for some reasons, one of > > which is performance. I though this had been largely optimized. Can't ruby refrain from instatiating the block as a proc until it is needed as such? If so then simply calling .call on the block reference could just trigger yield. That would give them nearly the same performance characteristics. T.
on 01.07.2006 03:14
While to anybody else this code made things clear, for me it is still a little bit confusing: why outer12 is performing slower than outer22? According to prev posts, I have understood that the usage of block.call requires a conversion to a Proc and this is slower. But in above case where is this conversion taking place? (or simply, why is it slower?). thanks (and sorry to be confused), ./alex -- .w( the_mindstorm )p. --- (http://themindstorms.blogspot.com)
on 01.07.2006 23:53
Alexandru Popescu wrote:
> While to anybody else this code made things clear, for me it is still
> a little bit confusing:
>
> why outer12 is performing slower than outer22?
>
> According to prev posts, I have understood that the usage of
> block.call requires a conversion to a Proc and this is slower. But in
> above case where is this conversion taking place? (or simply, why is
> it slower?).
>> def outer12(&bl)
>> inner2(&bl)
>> end
The conversion from block to a Proc object happens because of the &bl in
the above definition. When outer12 is actually called, the Proc is
instantiated and the variable bl is bound to it.
>> def outer22
>> inner2 {yield}
>> end
No & here, so no Proc is created.
on 02.07.2006 00:42
Thanks Joel... it looks like my initial understanding was wrong. It is not block.call the one that triggers block to Proc conversion, but in fact passing blocks as parameters. Is this the correct understanding? ./alex -- .w( the_mindstorm )p. --- (http://themindstorms.blogspot.com)
on 02.07.2006 02:07
Alexandru Popescu wrote: > Thanks Joel... it looks like my initial understanding was wrong. It is > not block.call the one that triggers block to Proc conversion, but in > fact passing blocks as parameters. Is this the correct understanding? Right, it happens when the block is passed to a method that expects a "&block" argument (or if the method explicitly calls Proc.new). If you are executing "block.call", then "block" is a variable and it, like any variable, refers to an object. It's up to the callee, not the caller, to determine how to treat the block: either yield to it or turn it into an object. The former has a small performance advantage (and yield is an elegant notation). The latter allows the Proc object to be saved away somewhere and called even after the method has finished.
on 03.07.2006 02:58
On Jul 1, 2006, at 8:05 PM, Joel VanderWerf wrote: > Alexandru Popescu wrote: >> Thanks Joel... it looks like my initial understanding was wrong. >> It is >> not block.call the one that triggers block to Proc conversion, but in >> fact passing blocks as parameters. Is this the correct understanding? > > Right, it happens when the block is passed to a method that expects > a "&block" argument (or if the method explicitly calls Proc.new). > If you are executing "block.call", then "block" is a variable and > it, like any variable, refers to an object. I like to compare these situations as 'explicit block argument' vs. 'implicit block argument'. You could also think of it as named vs. anonymous. In any case, as long as the block remains unnamed/ implicit there is no need to package it up into an explicit object (i.e. instance of Proc). It is the objectification step that burns up the extra cycles. Gary Wright
on 03.07.2006 03:16
Hi -- On Mon, 3 Jul 2006, gwtmp01@mac.com wrote: >> executing "block.call", then "block" is a variable and it, like any >> variable, refers to an object. > > I like to compare these situations as 'explicit block argument' vs. 'implicit > block argument'. You could also think of it as named vs. anonymous. In any > case, as long as the block remains unnamed/implicit there is no need to > package it up into an explicit object (i.e. instance of Proc). It is the > objectification step that burns up the extra cycles. I see it (subtly) differently. The block itself isn't an argument to the method; it's a syntactic construct, more analogous to the argument list than to a particular argument. In that capacity, it's always explicit; that is, it's written out as part of the method call (by definition). It's anonymous, but only in the sense that one could say an argument list is anonymous; there's no ArgumentList class for an argument list to be a named instance of, and no Block class for blocks to be named instances of, so anonymity is sort of a red herring. From that perspective, the objectification is entirely layered on top of the block; it doesn't change the status of the block per se. David -- David A. Black (dblack@wobblini.net) Ruby Power and Light, LLC (http://www.rubypowerandlight.com) See what the readers are saying about "Ruby for Rails"! http://www.rubypowerandlight.com/quotes