xx77aBs
xx77aBs

Reputation: 4768

Passing block from one method to another

I need to pass a block from one method to another (I want to call Rails.cache.fetch with block passed to my method).

I can either add &block 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
end

def with_yield
  do_something('Test') { yield }
end

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

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


&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 yield inside a newly created block?

Upvotes: 3

Views: 4247

Answers (1)

Tom Lord
Tom Lord

Reputation: 28285

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.

Upvotes: 4

Related Questions