xx77aBs xx77aBs - 5 months ago 8x
Ruby Question

Passing block from one method to another

I need to pass a block from one method to another (I want to call

with block passed to my method).

I can either add
to parameter list and use that to pass it to the next method, or I can create a new block and call yield inside of it. I've wrote a short example and benchmark:

require "benchmark"

def with_block(&block)
do_something 'Test', &block

def with_yield
do_something('Test') { yield }

def do_something(string)
"#{yield} #{string}"

n = 5_000_000
Benchmark.bmbm do |x|
x.report("&block") do
n.times { with_block { "Yo" } }
x.report("yield") do
n.times { with_yield { "Yo" } }

&block 3.320000 0.010000 3.330000 ( 3.340438)
yield 1.670000 0.000000 1.670000 ( 1.669504)
--------------------------------- total: 5.000000sec

user system total real
&block 3.270000 0.010000 3.280000 ( 3.275914)
yield 1.680000 0.000000 1.680000 ( 1.682768)

Looks like
{ yield }
approach is much faster. Is it the right way to go? Are there any gotchas I'm not aware of because of calling
inside a newly created block?


Short answer: Always use yield, unless you have a good reason to explicitly reference &block.

See: Why blocks make ruby methods 439% slower

With &block, you get a reified Proc on which you can do all kinds of stuff and which you can move around. However, with a yield and an implicit block, you are limited to only calling the block.

By using yield, the interpreter can bypass all the Proc reification as it knows the developer won't be able to use it; hence it can keep just a C-level structure instead of having to set up a Ruby-level object.