Skip to content

LocalJumpError raised on break from custom Enumerator enumeration #1270

@tdg5

Description

@tdg5

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!

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions