# Eval and implicit passing of blocks

**URL:** <https://www.ruby-forum.com/t/eval-and-implicit-passing-of-blocks/182996>\
**Category:** Ruby\
**Created:** [February 5, 2010, 7:07pm UTC](https://www.ruby-forum.com/t/eval-and-implicit-passing-of-blocks/182996 "2010-02-05T19:07:39Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Peter\_McLain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ecae2f/32.png) [@Peter\_McLain](https://www.ruby-forum.com/u/Peter_McLain)\
**Post date:** [February 5, 2010, 7:07pm UTC](https://www.ruby-forum.com/t/eval-and-implicit-passing-of-blocks/182996/1 "2010-02-05T19:07:39Z")

</div>

Hi,

I’m trying to understand if/how/when/why Ruby implicitly passes  
blocks to  
instance\_eval, class\_eval and eval, but not to plain methods.

It seems that 1.9 behavior is consistent across all versions of  
eval: a  
block, passed into a method that does an eval, is available for use  
by  
that eval. It also seems that 1.8.x has a bug in that the first  
level  
method called does not make the block available to eval, but that  
it is available to more deeply nested method calls.

```
   class Mystery1
     def level_1(&block)
       level_2(&block)

       # 1.8.x: LocalJumpError ; 1.9.x: Ok
       puts "Mystery1 level_1: #{instance_eval('yield')}"
     end

     def level_2(&block)
       level_3(&block)
       puts "Mystery1 level_2: #{instance_eval('yield')}" # OK
     end

     def level_3(&block)
       puts "Mystery1 level_3: #{instance_eval('yield')}" # OK
     end
   end

   o = Mystery1.new
   begin
     o.level_1 { 12 }
   rescue Exception => e
     puts "#{o.class} raised #{e.class}: #{e.message}"
     p e.backtrace
   end

```

Running this against 1.8.[67] and 1.9.2 gives different results:

```
   ruby-1.8.6-tv1_8_6_398: ruby 1.8.6 (2010-02-04 patchlevel 398)

```

[i686-darwin9.8.0]

```
   Mystery1 level_3: 12
   Mystery1 level_2: 12
   Mystery1 raised LocalJumpError: (eval):1:in `level_1': no block

```

given  
["/Users/pmclain/tmp/m1.rb:6:in `level\_1’", “/Users/pmclain/tmp/  
m1.rb:21”]

```
   ruby-1.8.7-p249: ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-

```

darwin9.8.0]

```
   Mystery1 level_3: 12
   Mystery1 level_2: 12
   Mystery1 raised LocalJumpError: (eval):1:in `level_1': no block

```

given  
["/Users/pmclain/tmp/m1.rb:6:in `level\_1’", “/Users/pmclain/tmp/  
m1.rb:21”]

```
   ruby-1.9.2-tv1_9_2_preview2: ruby 1.9.2dev (2009-09-07 trunk

```

1. [i386-darwin9.8.0]

Question 1: Is the 1.8 behavior a bug?

Question 2: Is the 1.9 behavior intended? If so, is it documented  
anywhere? Perhaps the various eval methods should document that  
they pass  
the calling frame’s block to the eval.

If I replace “instance\_eval” with “Mystery1.class\_eval”, I get the  
same  
result. If I replace “instance\_eval” with “eval”, I get different  
results:

```
   ruby-1.8.6-tv1_8_6_398: ruby 1.8.6 (2010-02-04 patchlevel 398)

```

[i686-darwin9.8.0]

```
   Mystery1 raised LocalJumpError: (eval):1:in `level_3': no block

```

given  
["/Users/pmclain/tmp/m1.rb:15:in `level_3'", "/Users/pmclain/ tmp/m1.rb:10:in`eval’", “/Users/pmclain/tmp/m1.rb:15:in `level_3'", "/ Users/pmclain/tmp/m1.rb:10:in`level\_2’”, “/Users/pmclain/tmp/m1.rb:  
3:in `level\_1’”, “/Users/pmclain/tmp/m1.rb:21”]

```
   ruby-1.8.7-p249: ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-

```

darwin9.8.0]

```
   Mystery1 raised LocalJumpError: (eval):1:in `level_3': no block

```

given  
["/Users/pmclain/tmp/m1.rb:15:in `level_3'", "/Users/pmclain/ tmp/m1.rb:10:in`eval’", “/Users/pmclain/tmp/m1.rb:15:in `level_3'", "/ Users/pmclain/tmp/m1.rb:10:in`level\_2’”, “/Users/pmclain/tmp/m1.rb:  
3:in `level\_1’”, “/Users/pmclain/tmp/m1.rb:21”]

```
   ruby-1.9.2-tv1_9_2_preview2: ruby 1.9.2dev (2009-09-07 trunk

```

1. [i386-darwin9.8.0]

So it looks like 1.9 is consistent in making the block available to  
eval  
at all levels, but 1.8 treats eval differently than class\_eval and  
instance\_eval.

It also looks like 1.8 has another bug in that it tries too hard to  
pass blocks along, whereas 1.9 gives reasonable behavior. In  
Mystery2 I  
don’t pass the block from level\_2 to level\_3, and 1.9 complains  
that no  
block was given; 1.8 seems to pass the block implicitly…

```
   class Mystery2
     def level_1(&block)
       level_2(&block)

       # 1.8.x: LocalJumpError ; 1.9.x: Ok
       #puts "Mystery2 level_1: #{instance_eval('yield')}"
     end

     def level_2(&block)
       level_3
       puts "Mystery2 level_2: #{instance_eval('yield')}" # OK
     end

     def level_3
       puts "Mystery2 level_3: #{instance_eval('yield')}" # 1.8:

```

OK 1.9: LocalJumpError  
end  
end

```
   o = Mystery2.new
   begin
     o.level_1 { 12 }
   rescue Exception => e
     puts "#{o.class} raised #{e.class}: #{e.message}"
     p e.backtrace
   end

```

And the output:

```
   ruby-1.8.6-tv1_8_6_398: ruby 1.8.6 (2010-02-04 patchlevel 398)

```

[i686-darwin9.8.0]

```
   Mystery2 level_3: 12
   Mystery2 level_2: 12

   ruby-1.8.7-p249: ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-

```

darwin9.8.0]

```
   Mystery2 level_3: 12
   Mystery2 level_2: 12

   ruby-1.9.2-tv1_9_2_preview2: ruby 1.9.2dev (2009-09-07 trunk

```

1. [i386-darwin9.8.0]

Question 3: Is the 1.8 behavior a bug?  
Question 4: Is the 1.9 behavior correct?

Is there any documentation (other than the code) that describes  
this in  
detail? Neither the Pick Axe book, nor the Flanagan/Matz book give  
detail on this. The RubySpecs also seem silent on this.

–  
Peter McLain  
removed\_email\_address@domain.invalid
