Reputation: 35084
Why does this snippet:
def dump_dump
get_dump = lambda do
return 1 if $n
$n = true
module_exec &get_dump
2
end
p get_dump[]
end
Module.new do
module_exec &method(:dump_dump)
end
print 2
in ruby 2.0.0p481 (2014-05-08) [x64-mingw32]
but 1
in jruby 1.7.15 (1.9.3p392) 2014-09-03 82b5cc3 on Java HotSpot(TM) 64-Bit Server VM
1.7.0_67-b01 +jit [Windows 8-amd64]?
I would like to understand the issue.
UPD: should it be reported somewhere?
Upvotes: 4
Views: 374
Reputation: 15965
I was always under the impression that return
inside a block was undefined behavior. Can you use next
instead?
For instance, Rubinius also has this problem but is much more explicit:
[1].map(&lambda { |n| return -1 })
LocalJumpError: unexpected return
Of course, using next
produces the expected results:
rbx-head :003 > [1].map(&lambda { |n| next -1 })
=> [-1]
The moral of the story is that return
is defined for methods, and Procs and lambdas are not methods. next
and break
are the keywords to use if you wish to stop a block call.
I can't find any documentation about return
's behavior from the official Ruby spec, but rubyspec
does have tests that verify return
causes the calling method to return.
https://github.com/rubyspec/rubyspec/blob/master/language/return_spec.rb#L184
Upvotes: 2
Reputation: 1555
A 'return' inside a lambda should return from the lambda and not return from the method. In this tricky case, it looks like jruby is not respecting the inner lambda, and instead returning all the way back to the first lambda call.
At first I thought it might be caused by a lambda call within a lambda, but now I believe it to be an issue related to block-conversion, after reducing the example down to this:
Module.new do
test = lambda do
return
end
module_exec &test
puts 'after'
end
Here only mri prints 'after', while jruby prints nothing.
...but if we do NOT do lambda to block conversion (the &test):
Module.new do
test = lambda do
return
end
module_exec { test[] }
puts 'after'
end
both mri and jruby print 'after'...
Upvotes: 0