Whilst profiling the performance of some code, I wondered why a method that was yielding to a small block of code was taking so long.
The answer was in the method arguments where out of habit I automatically capture the block argument and convert it to a proc using the ampersand (&) operator. When yielding to code that you are passing to a method, there is no need to convert the block to a proc as the block of code that you are yielding to is already a proc in the correct context.
An example to clarify:
# if you just want to yield to code, this way is inefficient
# as the block argument will be converted to a proc
def foo(argument, &block)
if some_logic
block.call # if we are just yielding to the block in the
# context it is already in, this is unnecessary.
end
end
# if you are just yielding to code, this way is better
def bar(argument)
if some_logic
yield # much better, there was no overhead
# of converting the block into a proc
end
end
# called like so
bar(my_argument) { p "Hello" }
Blocks and procs are complicated, here are a couple of resources: