-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
I have little to no experience with JRuby, so it's possible I'm doing this wrong, but while I was working to make a library I'm developing JRuby compatible, I ran into some weirdness with the Enumerator class.
Long story short, breaking from a custom Enumerator raises "LocalJumpError: break from proc-closure". This same behavior is not observed when breaking from an enumerator obtained via Range#to_enum. I understand this may be related to how the enumerator is created by Range, so I would be open to suggestions on how I might refactor the code below to support break.
I looked through the specs and came across TestIterator#test_ljump which made it seem that a LJE when breaking from a block may be the desired behavior. However, the same spec also makes it seem like a break from a lambda should not raise a LJE. To this end I also tried building an Enumerator using a lambda to determine if that fixed the issue, however a LJE is still raised, though with a different message.
Here is some code I wrote up to demonstrate this issue. This same code does not raise an error when run against MRI 1.9.3 or 2.0.0. However for JRuby, I found this code raises a LJE in both 1.9 and 2.0 mode of JRuby 1.7.6 and 1.7.8. I'm running Ubuntu 12.04 and I've included full ruby -v lines at the end of the issue.
unbreakable.rb:
class Unbreakable
def range_enumerator
(0..10).to_enum
end
def block_enumerator
Enumerator.new do |yielder|
10.upto(20) do |i|
yielder << i
end
end
end
def lambda_enumerator
Enumerator.new(&(lambda do |yielder|
20.upto(30) do |i|
yielder << i
end
end))
end
end
def main
unbreakable = Unbreakable.new
puts "Range#to_enum class: #{unbreakable.range_enumerator.class}"
puts "Enumerator instance w/ block class: #{unbreakable.block_enumerator.class}"
puts "Enumerator instance w/ lambda class: #{unbreakable.lambda_enumerator.class}"
count = 0
unbreakable.range_enumerator.each do |x|
puts x
break if 5 == count += 1
end
count = 0
begin
unbreakable.block_enumerator.each do |x|
puts x
break if 5 == count += 1
end
rescue => e
puts "Fail: #{e.inspect}"
end
count = 0
begin
unbreakable.lambda_enumerator.each do |x|
puts x
break if 5 == count += 1
end
rescue => e
puts "Fail: #{e.inspect}"
end
end
main
MRI output:
$ ruby unbreakable.rb
Range#to_enum class: Enumerator
Enumerator instance w/ block class: Enumerator
Enumerator instance w/ lambda class: Enumerator
0
1
2
3
4
10
11
12
13
14
20
21
22
23
24
JRuby output:
Range#to_enum class: Enumerator
Enumerator instance w/ block class: Enumerator
Enumerator instance w/ lambda class: Enumerator
0
1
2
3
4
10
11
12
13
14
Fail: #<LocalJumpError: break from proc-closure>
20
21
22
23
24
Fail: #<LocalJumpError: unexpected break>
My full ruby -v are:
jruby 1.7.6 (1.9.3p392) 2013-10-22 6004147 on OpenJDK 64-Bit Server VM 1.7.0_25-b30 [linux-amd64]
jruby 1.7.8 (1.9.3p392) 2013-11-14 0ce429e on OpenJDK 64-Bit Server VM 1.7.0_25-b30 [linux-amd64]
Please let me know if I can answer any questions or provide any additional information!