From: "zverok (Victor Shepelev) via ruby-core" Date: 2023-01-11T08:47:33+00:00 Subject: [ruby-core:111779] [Ruby master Feature#19324] Enumerator.product => Enumerable#product Issue #19324 has been updated by zverok (Victor Shepelev). First, I just looked through codebases at my disposal, and it seems that for `product` there are at least as many examples where the first argument _has_ a special meaning as those where it doesn't. Examples are like: ```ruby user_names.product(['']) # => [['name1', ''], ['name2' ''], ...] # this is the format some API requires, and .product is a simplest way to produce it possible_methods.product(possible_arguments) #=> list of test cases to check the stability of methods for all known arguments users.product(%i[original thumbnail]) #=> then produce big and small avatar for all of them ``` Or, in `ruby/lib`, there are exactly 3 entries, of which _two_ have distinct arguments: ``` $ grep -F "product(" lib -r lib/did_you_mean/tree_spell_checker.rb: states = plausibles[0].product(*plausibles[1..-1]) lib/bundler/spec_set.rb: handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h lib/bundler/spec_set.rb: deps = dependencies.product(platforms) ``` Rubocop (both entries have distinct arguments): ``` $ grep -F "product(" {lib,spec} -r lib/rubocop/config_obsoletion.rb: cops.product(parameters).map do |cop, parameter| spec/rubocop/cop/style/self_assignment_spec.rb: %i[+ - * ** / | & || &&].product(['x', '@x', '@@x']).each do |op, var| ``` **But second and more important,** the same argument (it is a method that operates on homogenous parameters, why it belongs to the first parameter?..) can be applied to a lot of methods. Like the aforementioned `Array#zip`, or `Hash#merge` (there are a lot of cases when we are just merging several homogenous hashes), or, well, even `a + b`! But multi-parameter methods consistently belong to their first parameters throughout Ruby, save for several methods in `Math` maybe (which, honestly, always felt like a compromise or legacy). So, the question is: is there a design plan to change _many_ of the methods (`Array.product` in addition to `Enumerable.product`, `Array.zip`, `Hash.merge`, I dunno, maybe even `Array.concat`?..) to the `Module.method` protocol? Or, would `Enumerable.product` be the **only** sore exclusion from what is consistently done throughout Ruby?.. ---------------------------------------- Feature #19324: Enumerator.product => Enumerable#product https://bugs.ruby-lang.org/issues/19324#change-101193 * 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 # (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/ ______________________________________________ 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/postorius/lists/ruby-core.ml.ruby-lang.org/