From: "zverok (Victor Shepelev) via ruby-core" Date: 2025-12-14T10:19:05+00:00 Subject: [ruby-core:124196] [Ruby Bug#21780] Change the default size of Enumerator.produce back to infinity Issue #21780 has been updated by zverok (Victor Shepelev). Description updated > I think `Enumerator#size` should only be non-nil when it is known to be the exact size. > In this case it is not know if it is infinite, so returning `Float::INFINITY` for the size is "wrong". I would argue that it is _known_ to be infinite: that's how `produce` works: loops infinitely, unless explicitly stopped by an _exception_, there is no other way than _an exceptional one_ (while this might seem to be a dumb pun, I actually think that we have a useful distinction here). So I would argue that the _default_ expectation of the user to "not think about it and trust Ruby to do the sane thing", and the sane thing is "`produce` is infinite unless you raise that specific exception" (even `break` wouldn't work... which is kinda unpleasant, but a discussion for another time). In a rare situation when they'd _question_ the behavior, there is a clearly documented way to adjust it. > BTW, your examples use `Enumerator.new` but the text seems to be about `Enumerator.produce`. Yes, thank you, fixed. ---------------------------------------- Bug #21780: Change the default size of Enumerator.produce back to infinity https://bugs.ruby-lang.org/issues/21780#change-115670 * Author: zverok (Victor Shepelev) * Status: Open * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- In #21701 a new argument `size:` was introduced, and its default value is `nil` (unknown). While I support the new argument, I'd argue that the default should be `Float::INFINITY`. **Reasoning:** By _design_, `Enumerator.produce` is infinite (there is no internal condition to stop iteration), and the simplest, most straightforward usages of the method would produce _definitely infinite_ iterators, which the user than can limit with `take`, or `take_while` or similar methods. To produce the enumerator that will stop by itself requires explicit raising of `StopIteration`, which I expect to be a (slightly) advanced technique, and those who use it might be more inclined to provide additional arguments to clarify the semantics. While `Enumerator#size` is hardly frequently used now (other than in `#to_set`, which started the discussion), it might be in the future, and I believe it is better to stick with more user-friendly defaults. Now: ```ruby # very trivial enumerator, but if you want it to have "proper" size, you need # to not forget to use an elaborate argument and type additional 21 characters Enumerator.produce(1, size: Float::INFINITY, &:succ) # already non-trivial enumerator, which is hardly frequently used, but the # current defaults correspond to its semantics: Enumerator.produce(Date.today) { raise StopIteration if it.tuesday? && it.day.odd? it + 1 } ``` With my proposal: ```ruby # trivial, most widespread case: Enumerator.produce(1, &:succ).size #=> Infinity # non-trivial case, with the enumerator designer clarifying their # intention that "we are sure it stops somewhere": Enumerator.produce(Date.today, size: nil) { raise StopIteration if it.tuesday? && it.day.odd? it + 1 } ``` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/