Project

General

Profile

Bug #13064

Updated by jwmittag (Jörg W Mittag) about 3 years ago

[@Kalsan over on StackOverflow observed inconsistent behavior](http://stackoverflow.com/q/41283514/2988) with `next` inside `begin`/`end` across different implementations. In particular, Rubinius, JRuby, and MRuby all behave the same while YARV behaves differently. In addition, running the same code inside IRb behaves differently than running it as a script. 

 Usually, YARV is the gold standard, and if some behavior differs from YARV, YARV is right and the other implementation is wrong. However, in this case, not only do *all other* implementations disagree with YARV, but in particular, MRuby/Rite, the implementation written and maintained by matz himself disagrees with YARV. 

 So, what is the correct behavior for this (admittedly) non-sensical code? 

 Here is the behavior across different versions of YARV and different implementations: 

 * YARV 2.2.0 (the build shipping with macOS) 

         # ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16] 
         -e:1: warning: statement not reached 
         -e:1: Invalid next 
         -e: compile error (SyntaxError) 

         # irb -f -d -w -W 
         irb(main):001:0> p RUBY_VERSION 
         "2.0.0" 
         => "2.0.0" 
         irb(main):002:0> p RUBY_ENGINE 
         "ruby" 
         => "ruby" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         (irb):9: warning: statement not reached 
         Exception `SyntaxError' at /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86 - (irb):7: Can't escape from eval with next 
         Exception `SyntaxError' at /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86 - (irb):7: Can't escape from eval with next 
         SyntaxError: (irb):7: Can't escape from eval with next 
        	 from (irb) 
         irb(main):011:0>  
         irb(main):012:0* exit 

 * YARV 2.3.1 (the version JRuby claims to be compatible with at the moment), 2.3.3, 2.4.0-preview3, moment) 

         # ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16] 
         -e:1: warning: statement not reached 
         -e: -e:1: Invalid next (SyntaxError) 

         # irb -f -d -w -W 
         irb(main):001:0> p RUBY_VERSION 
         "2.3.1" 
         => "2.3.1" 
         irb(main):002:0> p RUBY_ENGINE 
         "ruby" 
         => "ruby" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         (irb):9: warning: statement not reached 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.1/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         SyntaxError: (irb):7: Can't escape from eval with next 
        	 from (irb) 
         irb(main):011:0>  
         irb(main):012:0* exit 

 * YARV 2.3.3 

         # ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16] 
         -e:1: warning: statement not reached 
         -e: -e:1: Invalid next (SyntaxError) 

         # irb -f -d -w -W 
         irb(main):001:0> p RUBY_VERSION 
         "2.3.3" 
         => "2.3.3" 
         irb(main):002:0> p RUBY_ENGINE 
         "ruby" 
         => "ruby" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         (irb):9: warning: statement not reached 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.3/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.3/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.3.3/lib/ruby/2.3.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         SyntaxError: (irb):7: Can't escape from eval with next 
        	 from (irb) 
         irb(main):011:0>  
         irb(main):012:0* exit 

 * YARV 2.4.0-preview3: 

         # ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         ruby 2.4.0preview3 (2016-11-07 trunk 56661) [x86_64-darwin16] 
         -e:1: warning: statement not reached 
         -e: -e:1: Invalid next (SyntaxError) 

         # irb -f -d -w -W 
         irb(main):001:0> p RUBY_VERSION 
         "2.4.0" 
         => "2.4.0" 
         irb(main):002:0> p RUBY_ENGINE 
         "ruby" 
         => "ruby" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         (irb):9: warning: statement not reached 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.4.0-preview3/lib/ruby/2.4.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         SyntaxError: (irb):7: Can't escape from eval with next 
        	 from (irb) 
         irb(main):011:0>  
         irb(main):012:0* exit 

 * YARV 2.4.0-dev (current SVN trunk as of yesterday): 

         # ruby -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         ruby 2.4.0dev (2016-12-22 trunk 57151) [x86_64-darwin16] 
         -e:1: warning: statement not reached 
         -e: -e:1: Invalid next (SyntaxError) 

         # irb -f -d -w -W 
         irb(main):001:0> p RUBY_VERSION 
         "2.4.0" 
         => "2.4.0" 
         irb(main):002:0> p RUBY_ENGINE 
         "ruby" 
         => "ruby" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         (irb):9: warning: statement not reached 
         Exception `SyntaxError' at /Users/joerg/.rbenv/versions/2.4.0-dev/lib/ruby/2.4.0/irb/workspace.rb:87 - (irb):7: Can't escape from eval with next 
         SyntaxError: (irb):7: Can't escape from eval with next 
        	 from (irb) 
         irb(main):011:0>  
         irb(main):012:0* exit 

 * Rubinius 3.69 

         # rbx -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         rubinius 3.69 (2.3.1 a57071c6 2016-11-17 3.8.1) [x86_64-darwin15.6.0] 
         1 
                         main # Rubinius::Loader at core/loader.rb:860 
                        evals # Rubinius::Loader at core/loader.rb:646 
                         eval # Kernel(Rubinius::Loader) at core/kernel.rb:1130 
             call_on_instance # Rubinius::BlockEnvironment at core/block_environment.rb:147 
            { } in __script__ # Object at -e:1 
                   jump_error . Rubinius at core/rubinius.rb:279 

         invalid context for 'next' (LocalJumpError) 

         An exception occurred evaluating command line code 

         # irb 
         irb(main):001:0> p RUBY_VERSION 
         "2.3.1" 
         => "2.3.1" 
         irb(main):002:0> p RUBY_ENGINE 
         "rbx" 
         => "rbx" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         1 
         LocalJumpError: invalid context for 'next' 
        	 from core/rubinius.rb:279:in `jump_error' 
        	 from (irb):7 
        	 from core/block_environment.rb:147:in `call_on_instance' 
        	 from core/kernel.rb:1130:in `eval' 
        	 from core/kernel.rb:585:in `loop' 
        	 from core/proc.rb:20:in `call' 
        	 from core/kernel.rb:1067:in `catch' 
        	 from core/throw_catch.rb:8:in `register' 
        	 from core/kernel.rb:1066:in `catch' 
        	 from core/proc.rb:20:in `call' 
        	 from core/kernel.rb:1067:in `catch' 
        	 from core/throw_catch.rb:8:in `register' 
        	 from core/kernel.rb:1066:in `catch' 
        	 from core/code_loader.rb:505:in `load_script' 
        	 from core/code_loader.rb:590:in `load_script' 
        	 from core/loader.rb:679:in `script' 
        	 from core/loader.rb:861:in `main'irb(main):011:0>  
         irb(main):012:0* exit 

 * JRuby 9.1.6.0 (the latest release) 

         # jruby -v -W -e 'begin; begin puts 1; next end; puts 2 end' 
         jruby 9.1.6.0 (2.3.1) 2016-11-09 0150a76 Java HotSpot(TM) 64-Bit Server VM 25.102-b14 on 1.8.0_102-b14 +jit [darwin-x86_64] 
         1 
         LocalJumpError: unexpected next 
           <main> at -e:1 

         # irb -f -d -w -W 
         irb(main):001:0> p RUBY_VERSION 
         "2.3.1" 
         => "2.3.1" 
         irb(main):002:0> p RUBY_ENGINE 
         "jruby" 
         => "jruby" 
         irb(main):003:0>  
         irb(main):004:0* begin 
         irb(main):005:1*     begin 
         irb(main):006:2*       puts 1 
         irb(main):007:2>       next 
         irb(main):008:2>     end 
         irb(main):009:1>     puts 2 
         irb(main):010:1> end 
         1 
         => nil 
         irb(main):011:0>  
         irb(main):012:0* exit 

 * MRuby 1.2.0 (the minimal ISO compliant Ruby implementation written by matz himself) 

         # mruby -v -e 'begin; begin puts 1; next end; puts 2 end' 
         mruby 1.2.0 (2015-11-17)  
         00001 NODE_SCOPE: 
         00001     NODE_BEGIN: 
         00001       NODE_BEGIN: 
         00001         NODE_BEGIN: 
         00001           NODE_CALL: 
         00001             NODE_SELF 
         00001             method='puts' (383) 
         00001             args: 
         00001               NODE_INT 1 base 10 
         00001           NODE_NEXT: 
         00001         NODE_CALL: 
         00001           NODE_SELF 
         00001           method='puts' (383) 
         00001           args: 
         00001             NODE_INT 2 base 10 
         irep 0x7fe0e3c1b630 nregs=4 nlocals=1 pools=1 syms=1 reps=0 
         file: -e 
             1 000 OP_LOADSELF 	 R1 		
             1 001 OP_LOADI 	 R2 	 1 	
             1 002 OP_SEND 	 R1 	 :puts 	 1 
             1 003 OP_ERR 	 "unexpected next" 
             1 004 OP_LOADSELF 	 R1 		
             1 005 OP_LOADI 	 R2 	 2 	
             1 006 OP_SEND 	 R1 	 :puts 	 1 
             1 007 OP_STOP 

         1 
         trace: 
        	 [0] -e:1 
         LocalJumpError: unexpected next 

         # irb -v 
         mruby 1.2.0 (2015-11-17)  
         mirb - Embeddable Interactive Ruby Shell 

         > p RUBY_VERSION 
         00001 NODE_SCOPE: 
         00001     NODE_BEGIN: 
         00001       NODE_CALL: 
         00001         NODE_SELF 
         00001         method='p' (384) 
         00001         args: 
         00001           NODE_CONST RUBY_VERSION 
         irep 0x7fceeac05220 nregs=4 nlocals=1 pools=0 syms=2 reps=0 
         file: (mirb) 
             1 000 OP_LOADSELF 	 R1 		
             1 001 OP_GETCONST 	 R2 	 :RUBY_VERSION 
             1 002 OP_SEND 	 R1 	 :p 	 1 
             1 003 OP_STOP 

         "1.9" 
          => "1.9" 
         > p RUBY_ENGINE 
         00002 NODE_SCOPE: 
         00002     NODE_BEGIN: 
         00002       NODE_CALL: 
         00002         NODE_SELF 
         00002         method='p' (384) 
         00002         args: 
         00002           NODE_CONST RUBY_ENGINE 
         irep 0x7fceeae05cf0 nregs=4 nlocals=1 pools=0 syms=2 reps=0 
         file: (mirb) 
             2 000 OP_LOADSELF 	 R1 		
             2 001 OP_GETCONST 	 R2 	 :RUBY_ENGINE 
             2 002 OP_SEND 	 R1 	 :p 	 1 
             2 003 OP_STOP 

         "mruby" 
          => "mruby" 
         >  
         00004 NODE_SCOPE: 
         00004     NODE_BEGIN: 
         irep 0x7fceeac06a50 nregs=2 nlocals=1 pools=0 syms=0 reps=0 
         file: (mirb) 
             4 000 OP_LOADNIL 	 R1 		
             4 001 OP_STOP 

          => nil 
         > begin 
         00005 NODE_NIL 
         *     begin 
         00007 NODE_NIL 
         *       puts 1 
         00009 NODE_NIL 
         *       next 
         00011 NODE_NIL 
         *     end 
         00013 NODE_NIL 
         *     puts 2 
         00015 NODE_NIL 
         * end 
         00012 NODE_SCOPE: 
         00012     NODE_BEGIN: 
         00012       NODE_BEGIN: 
         00012         NODE_BEGIN: 
         00012           NODE_CALL: 
         00012             NODE_SELF 
         00012             method='puts' (383) 
         00012             args: 
         00012               NODE_INT 1 base 10 
         00013           NODE_NEXT: 
         00015         NODE_CALL: 
         00015           NODE_SELF 
         00015           method='puts' (383) 
         00015           args: 
         00015             NODE_INT 2 base 10 
         irep 0x7fceeae01130 nregs=4 nlocals=1 pools=1 syms=1 reps=0 
         file: (mirb) 
            12 000 OP_LOADSELF 	 R1 		
            12 001 OP_LOADI 	 R2 	 1 	
            12 002 OP_SEND 	 R1 	 :puts 	 1 
            13 003 OP_ERR 	 "unexpected next" 
            15 004 OP_LOADSELF 	 R1 		
            15 005 OP_LOADI 	 R2 	 2 	
            15 006 OP_SEND 	 R1 	 :puts 	 1 
            15 007 OP_STOP 

         1 
         LocalJumpError: unexpected next 
         >  
         00012 NODE_SCOPE: 
         00012     NODE_BEGIN: 
         irep 0x7fceeae078f0 nregs=2 nlocals=1 pools=0 syms=0 reps=0 
         file: (mirb) 
            12 000 OP_LOADNIL 	 R1 		
            12 001 OP_STOP 

          => nil 
         > exit 

 What is most interesting is that MRuby, JRuby and Rubinius actually agree on the behavior, but differ from YARV. Either YARV or all the other ones are wrong. I cannot say which ones, though.

Back