From: headius@... Date: 2020-04-24T20:36:20+00:00 Subject: [ruby-core:98060] [Ruby master Bug#16816] Prematurely terminated Enumerator should stay terminated Issue #16816 has been updated by headius (Charles Nutter). A simpler way to say why I believe this is a bug... If I have an Enumerator with custom logic, and it is constructed and used once, I expect the iteration block will be entered *exactly* once and exited *exactly* once. ---------------------------------------- Bug #16816: Prematurely terminated Enumerator should stay terminated https://bugs.ruby-lang.org/issues/16816#change-85287 * Author: headius (Charles Nutter) * Status: Open * Priority: Normal * ruby -v: all * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN ---------------------------------------- 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/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? -- https://bugs.ruby-lang.org/ Unsubscribe: