Issue #21780 has been updated by zverok (Victor Shepelev).
However, since that functionality actually exists, I think #size has no choice but to return nil.
Respectfully, I disagree. I think it is much easier _and more useful_ to explain it along the lines of... **It is infinite by implementation, but you can break it with _exception_ (which is, well, for _exceptional_ situations); if you care about size reporting, here is how you can adjust it (the new `size:` parameter introduced).** Yes, if you didn't pass it AND broken the enumerator, the `#size` "lies", but as the parameter exist, it is no different to "lie" in this situation: ```ruby e = Enumerator.new(5) { |y| 2.times { y << it } } e.size #=> 5 e.to_a.size #=> 2 ``` _If_ the user cares, they will appreciate "you have control, the defaults are sane for the _default_ usage". I agree there might be not many those who care, but the feature exists, and it exposes some semantics, and it might become more used in the future. The discussion is mostly theoretical, I agree. But I believe that _if_ Ruby 4.0 draws some attention to `Enumertor.produce`-enumerator sizes (by introducing the new parameter), it is better to use the most useful defaults. And I do believe that `Infinity` is the most useful. ---------------------------------------- Bug #21780: Change the default size of Enumerator.produce back to infinity https://bugs.ruby-lang.org/issues/21780#change-115744 * 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/