Feature #16816
Updated by headius (Charles Nutter) over 4 years ago
When iterating over an Enumerator, there are three different possible results of calling `next`: 1. The next item is returned and a cursor is advanced 2. There's no next item and the Enumerator will forever raise `StopIteration` 3. There's an error getting the next item which is raised out of `next` This third case has some unexpected behavior that I discovered while working on https://github.com/jruby/jruby/issues/6157 https://github.com/jruby/jruby/issue/6157 It seems that when an Enumerator fails prematurely with an exception, any subsequent call to #next will cause it to restart. This can be seen in a simple script I used to write a ruby/spec in https://github.com/jruby/jruby/pull/6190 ```ruby Enumerator.new { 2.times {|i| raise i.to_s } }.tap {|f| p 2.times.map { f.next rescue $!.message } } ``` The output from this is `[0, 0]`. After the iteration fails, the second `next` call causes it to restart and it fails again. Contrast this to the behavior of item 3 above; when an Enumerator finishes iterating without error, it remains "finished" forever and can't be restarted. I believe the restarting behavior is at best undocumented behavior and at worst incorrect and unspected. Take this example: ```ruby e = Enumerator.new { |y| c = new_database_cursor 5.times { y.yield c.next_result } } ``` If `next_result` here raises an error, a subsequent call to `next` on this enumerator will cause it to restart, re-acquire the cursor, and begin again. As another example I ask a question: how do you indicate that an Enumerator failed due to an error, and *keep it failed* so it doesn't restart again?