ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:98059] [Ruby master Bug#16816] Prematurely terminated Enumerator should stay terminated
@ 2020-04-24 20:34 headius
  2020-04-24 20:36 ` [ruby-core:98060] " headius
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: headius @ 2020-04-24 20:34 UTC (permalink / raw)
  To: ruby-core

Issue #16816 has been reported by headius (Charles Nutter).

----------------------------------------
Bug #16816: Prematurely terminated Enumerator should stay terminated
https://bugs.ruby-lang.org/issues/16816

* 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/

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-04-09 21:24 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-24 20:34 [ruby-core:98059] [Ruby master Bug#16816] Prematurely terminated Enumerator should stay terminated headius
2020-04-24 20:36 ` [ruby-core:98060] " headius
2020-04-24 22:04 ` [ruby-core:98061] " shevegen
2020-04-25  8:05 ` [ruby-core:98063] " headius
2020-05-07  8:17 ` [ruby-core:98176] " ko1
2020-05-07  8:25 ` [ruby-core:98177] " mame
2020-05-07 20:02 ` [ruby-core:98206] " eregontp
2020-12-21 13:46 ` [ruby-core:101587] " intrip
2021-04-09 21:24 ` [ruby-core:103355] [Ruby master Feature#16816] " merch-redmine

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).