Issue #15027 has been updated by jeremyevans0 (Jeremy Evans).


I'm against changing the current behavior.  If you can override `each`, you can override other methods.  If we wanted to be consistent about making this change, we would probably need to remove most the following additional core methods so that the Enumerable implementation would be used:

~~~
Array: any?, collect, count, cycle, drop, drop_while, find_index, first, include?, map, max, min, reject, reverse_each, select, sort, sum, take, take_while, to_a, to_h, uniq, zip
Hash: any?, include?, member?, to_a, to_h
Range: first, include?, max, member?, min
Struct: to_h
~~~

Above results generated with the following code (which includes some additional classes and methods):

~~~ ruby
classes = []
meths = Enumerable.instance_methods(false) - [:each]

ObjectSpace.each_object(Class){|c| classes << c if c < Enumerable && c.name}

classes.sort_by(&:name).each do |c|
  same = c.instance_methods(false) & meths
  next if same.empty?
  puts "#{c}: #{same.sort.join(', ')}"
end
~~~

I'm guessing the standard library would need additional changes (e.g. set).

If anyone really wants the default Enumerable behavior for Struct:

~~~ ruby
Struct.remove_method(:to_a, :to_h, :select)
~~~

----------------------------------------
Bug #15027: When Struct#each method is overriden Struct#select and Struct#to_a use wrong collections
https://bugs.ruby-lang.org/issues/15027#change-73705

* Author: bruno (Bruno Sutic)
* Status: Feedback
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 2.6.0dev
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
### Bug

Here's the code snippet that should reproduce the problem:

~~~ ruby
class Foo < Struct.new(:bar)
  def each(&block)
    [:baz, :qux].each(&block)
  end
end

foo = Foo.new(:foo)
foo.map(&:itself) # => [:baz, :qux]  # OK

foo.to_a # => [:foo]  # NOT OK, expected [:baz, :qux]
foo.select(&:itself) # => [:foo]  # NOT OK, expected [:baz, :qux]
~~~

As you can see, even tho we defined another collection for use by overriding `#each`, the `to_a` and `select` still use `Struct`'s original collection.

The problem seem to be with `Struct#to_a` and `Struct#select` methods from `struct.c` file that are defined unnecessarily.

### Proposed solution

The attached solution simply deletes `Struct#select` and `Struct#to_a`. A couple tests are added to show everything still works as before.

Please let me know if I can provide any more info and I'll be ready to do so.

---Files--------------------------------
struct_enumerable_fix.patch (2.8 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>