There are two main ways to receive blocks in a method in Ruby:
the first is to use the yield keyword like so:

defspeakputsyieldendspeak{"Hello"}# Hello# => nil

The other is to prefix the last argument in a method signature with an
ampersand which will then create a Proc object from any block passed
in. This object can then be executed with the call method like so:

defspeak(&block)putsblock.callendspeak{"Hello"}# Hello# => nil

The problem with the second approach is that instantiating a new Proc object incurs
a surprisingly heavy performance penalty as detailed by Aaron Patterson in his
excellent RubyConf X presentation, “ZOMG WHY IS THIS CODE SO SLOW?”
(beginning around the 30 minute mark or from slide 181).

This can easily be verified with the following benchmark, block_benchmark.rb:

So it is clearly preferable to choose yield over &block but what if you need to
pass a block to another method?

For example, here is a class that implements a method tell_ape which delegates to
another, more generic method named tell. This sort of pattern is commonly done
using method_missing but I’ll keep the methods explicit for
simplicity:

Of course, if you do use Proc.new then you lose the performance benefit of using
only yield (as Proc objects are being created as with &block) but it does
avoid unnecessary creation of Proc objects when you don’t need them. This can be
demonstrated with the following benchmark, proc_new_benchmark.rb:

require"benchmark"defsometimes_block(flag,&block)ifflag&&blockblock.callendenddefsometimes_proc_new(flag)ifflag&&block_given?Proc.new.callendendn=1_000_000Benchmark.bmbmdo|x|x.report("&block")don.timesdosometimes_block(false){"won't get used"}endendx.report("Proc.new")don.timesdosometimes_proc_new(false){"won't get used"}endendend

The key here is that using &block will always create a new Proc object,
even if we don’t make use of it. By using Proc.new only when we actually
need it, we can avoid the cost of this object instantiation entirely.

That said, there is a potential trade-off here between performance and
readability: it is clear from the sometimes_block method signature that it
takes a block and therefore will presumably do something with it; the same cannot
be said for the more efficient sometimes_proc_new.

In the end, it comes down to your specific requirements but it is still a useful
language feature to know.