Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing block from one method to another

Tags:

ruby

proc

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?

like image 207
xx77aBs Avatar asked Jan 21 '26 08:01

xx77aBs


1 Answers

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.

like image 134
Tom Lord Avatar answered Jan 23 '26 17:01

Tom Lord