Issue #19324 has been updated by duerst (Martin Dürst).
For `product`, one important issue not yet mentioned here is whether it's calculated
on e.g. two or three separate arrays, where making the first of the arrays the receiver,
or whether it's calculated on an array of arrays where the first of the arrays
doesn't have any special significance.
In the second case, writing e.g.
`[0, 1].product([0, 1], [0, 1])` feels rather inappropriate. But this case in my
experience is actually rather more frequent than having a first array that is in some way
special. Even more, if the array of arrays is already a variable, it gets rather
involved:
```
array_of_arrays = [[0, 1]] * 3
# => [[0, 1], [0, 1], [0, 1]]
array_of_arrays.first.product(*array_of_arrays.drop(1))
# =>
# [[0, 0, 0],
# [0, 0, 1],
# [0, 1, 0],
# [0, 1, 1],
# [1, 0, 0],
# [1, 0, 1],
# [1, 1, 0],
# [1, 1, 1]]
```
`Enumerator.product` makes that more straightforward:
`Enumerator.product(*array_of_arrays)`. (In my purely personal opinion, the need for the
`*` is still a nuissance, but only a small one.)
Having these two invocations distinguished by whether the method is an instance method or
a class method to some extent makes sense, although being able to use the instance method
directly on an array of arrays might also make some sense. Having the instance method on
Array and the class method on Enumerator seems something that could be improved without
any backwards compatibility problems.
That still leaves the problem that I really would like to write `array_of_arrays.product`,
in particular in a method chain. That will be difficult to get to because of backward
compatibility problems.
----------------------------------------
Feature #19324: Enumerator.product => Enumerable#product
https://bugs.ruby-lang.org/issues/19324#change-101147
* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
----------------------------------------
I know it might be too late after introducing a feature and releasing a version, but I
find `Enumerator.product` quite confusing, and can't find any justification in
#18685.
**Problem 1: It is `Array#product` but `Enumerator.product`**
```ruby
[1, 2].product([4, 5])
# => [[1, 4], [1, 5], [2, 4], [2, 5]]
# Usually, when we add methods to Enumerable/Enumerator which
# already array had before, it is symmetric, say...
[1, nil, 2, 3].compact #=> [1, 2, 3]
[1, nil, 2, 3].lazy.compact.first(2) #=> [1, 2]
# But not in this case:
[1, 2].lazy.product([4, 5]).first(2)
# undefined method `product' for #<Enumerator::Lazy: [1, 2]> (NoMethodError)
# Because you "just" need to change it to:
Enumerator.product([1, 2].lazy, [4, 5]).first(2)
# => [[1, 4], [1, 5]]
```
No other method was "promoted" from Array this way
And in general, I believe core methods tend to belong to the first object in the
expression and not be free module methods, Elixir style.
**Problem 2: It is one letter different from `Enumerator.produce`**
I understand I might be biased here (as a person who proposed `produce`), and that method
is not as popular (yet?) as I hoped, but still, two methods that do completely different
things and differ by one letter, both being somewhat vague verbs (so it is easy to confuse
them unless you did a lot of math and "product" is firmly set for set product in
your head).
I believe that EITHER of two problems would be concerning enough, but the combination of
them seems to be a strong enough argument to make the change?.. (Maybe with graceful
deprecation of module method in one next version, but, considering the Ruby 3.2 is just
released, maybe vice versa, fix the problem in the next minor release?..)
--
https://bugs.ruby-lang.org/