Issue #21780 has been updated by zverok (Victor Shepelev).
However, the change that made Enumerator#to_set refuse to operate when the size returns infinity introduced a compatibility issue
TBH, I don't see the compatibility argument applied with any consistency here. Let's imagine several cases: 1) Somebody relies on constructing elaborate `Enumerator.produce`-based enumerators that throw `StopIteration` to terminate (instead of using simpler techniques), and then applies `#to_set` to them. In this feature, we are keeping compatibility for them. 2) Somebody uses `Enumerator.produce` alongside other types of enumerators. In some branch of their code, they do `raise "Can't do this operation" if enum.size == Float::INFINITY`. The compatibility is broken for them. 3) Somebody relies on `Enumerator.produce { ... }.take(5)` to have non-`nil` size, throwing it around as a duck-typed array. The compatibility is broken for them. 4) (Just to expand the scope of _possible_ compatibility studies) Somebody might've suddenly had code like this, and it is now also broken: ```ruby Enumerator.produce(size: 5) { it.merge(size: it[:size] + 1) }.take(8) #=> [{size: 5}, {size: 6}, {size: 7}, {size: 8}, {size: 9}, {size: 10}, {size: 11}, {size: 12}] ``` Intuitively, I would say that (2) is the most basic case that shouldn't be broken; (3) is a (weak) evidence to the same; while both (1) and (4) are both a "collateral damage" that should be accepted (because if we treat compatibility with any real rigor, no changes should be made at all, "any change breaks _somebody's_ usecase"). Is there any study that I am not aware of that says that (1) is the widespread case and breaking it will outrage a huge part of the community, while breaking 2-3 (_as well as_ the general semantics of the method) is negligible? Or maybe there is some evidence/discussion that it is authors of elaborate enumerators who wouldn't understand a very small (and well-explained semantically) change to fix the incompatibility, while those who would expect this enumerator to be infinite should just swallow it and add `size: Float::INFINITY` maybe in a dozen places in their code? What am I missing here? ---------------------------------------- Bug #21780: Change the default size of Enumerator.produce back to infinity https://bugs.ruby-lang.org/issues/21780#change-115710 * 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/