Issue #21780 has been updated by zverok (Victor Shepelev).
This is where you are mistaken.
No, that's exactly what I've meant: ```ruby # case 1: e = Enumerator.produce(1, size: Float::INFINITY) {it>=3 ? raise(StopIteration) : it+1} p e.to_set # ruby 3.4: #<Set: {1, 2, 3}> # master: Set[1, 2, 3] # master with my proposed fix (size: Infinity by default): # cannot convert an infinite enumerator to a set (ArgumentError) -- compatibility broken # fix for the code authors: e = Enumerator.produce(1, size: nil) {it>=3 ? raise(StopIteration) : it+1} # -- clear change, easy to explain # Another possible fix, "come to think about it, I don't need StopIteration!" e = Enumerator.produce(1) { it + 1 }.take_while { it <= 3 }.to_set #=> Set[1, 2, 3] # case 2: e = Enumerator.produce(1, &:succ) if e.size == Float::INFINITY puts "Early stop processing!" # in reality, probably raise/early return else puts "Continue processing" end # ruby 3.4: "Early stop processing" # master: "Continue processing" -- compatibility broken # fix for the code authors: Enumerator.produce(1, size: Float::INFINITY, &:succ) # -- ugly change to trivial code # master with my proposed fix (size: Infinity by default): "Early stop processing" -- compatibility OK # case 3: e = Enumerator.produce(1, &:succ).lazy.take(6) p e.size # ruby 3.4: 6 # master: nil -- compatibility broken # master with my proposed fix: 6 -- compatibility OK ``` Why do we consider that case (1) of those is the one where we preserve compatibility, while two other should be broken, and not vice versa? ---------------------------------------- Bug #21780: Change the default size of Enumerator.produce back to infinity https://bugs.ruby-lang.org/issues/21780#change-115724 * 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/