Why does the break statement in ruby behave differently when using Proc.new v. the ampersand sign?

proc-object, ruby, ruby-on-rails

Solution

`break` makes the block and the caller of the block return. In the following code:

proc = Proc.new { break }

The "caller" of the block which is converted to a Proc object is Proc.new. `break` is supposed to make the caller of the block return, but Proc.new has already returned.

In this code:

def iterator(&b); b.call; end
iterator { break }

The caller of the block is `iterator`, so it makes `iterator` return.

Problem

The break statement for blocks (as per The Ruby Programming Language) is defined as follows: it causes the block to return to its iterator and the iterator to return to the method that invoked it. Therefore when the following code is run, it results in a LocalJumpError. ``` def test puts "entering test method" proc = Proc.new { puts "entering proc"; break } proc.call # LocalJumpError: iterator has already returned puts "exiting test method" end test ``` While the following code does not throw a LocalJumpError. What is special about the ampersand sign? Doesn't the ampersand sign implicitly use Proc.new? ``` def iterator(&proc) puts "entering iterator" proc.call # invoke the proc puts "exiting iterator" # Never executed if the proc breaks end def test iterator { puts "entering proc"; break } end test ``` In other words, I read the ampersand sign as a means of in-lining the Proc.new call. At which point the behavior should be just the same as the first code snippet. ``` def iterator (p = Proc.new { puts "entering proc"; break}) ... end ``` Disclaimer: I am newb learning the language (ruby 1.9.2), and therefore will appreciate references and a detailed synopsis.

Original source