Why does the break statement in ruby ​​behave differently when using Proc.new v. Ampersand symbol?

The break statement for blocks (according to the Ruby programming language ) is defined as follows:

it forces the block to return to its iterator and iterator in order to return to the method that called it.

Therefore, when the following code is executed, this results in a LocalJumpError error.

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 execute , a LocalJumpError is raised. What is special about the ampersand? Does 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 am reading the ampersand sign as a means of connecting the call to Proc.new. In this case, the behavior should be the same as the first piece of code.

 def iterator (p = Proc.new { puts "entering proc"; break}) ... end 

Disclaimer I am learning the language (ruby 1.9.2) and therefore I will be grateful for the links and a detailed review.

+7
source share
3 answers

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

 proc = Proc.new { break } 

The β€œcalling” block that maps to the Proc object is Proc.new. break assumes the caller is returning, but Proc.new has already been returned.

In this code:

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

The calling block is an iterator , so it returns an iterator .

+6
source

Here is the answer .

Ampersand is used to convert proc to block and block to proc.

I modified the example to relate your case:

 def run_my_code(&my_code) puts 'before proc' my_code.call puts 'after proc' end run_my_code { puts "passing a block, accepting a proc"; break} => before proc passing a block, accepting a proc 

As you can see, he did not get to 'after proc'

 def run_my_code yield end my_proc = Proc.new { puts "passing a proc instead of block"; break} run_my_code &my_proc => passing a proc instead of block LocalJumpError: break from proc-closure from (pry):75:in `block in <main>' 

In your second example, you have the result of proc, proc breaks with the iterator and returns to the test function.

 def iterator(&proc) puts 'entering iterator' proc.call puts 'exiting iterator' end def test puts 'before test' iterator { puts 'entering proc'; break } puts 'after test' end =>before test entering iterator entering proc after test 
+3
source

This is due to the difference between blocks, procs and lambdas - and their respective areas.

I wrote a post about this back in 2009, which you might find useful: http://www.leonardoborges.com/writings/2009/07/22/procs-lambdas-blocks-whats-the-difference/

Hope this helps.

0
source

All Articles