From: Marc-Andre Lafortune Date: 2012-03-02T10:50:47+09:00 Subject: [ruby-core:43042] [ruby-trunk - Bug #6087] How should inherited methods deal with return values of their own subclass? Issue #6087 has been updated by Marc-Andre Lafortune. Assignee set to Yukihiro Matsumoto Hi, Thomas Sawyer wrote: > I would think these methods should be using `self.class.new` for constructors thus returning the subclass. Although, that might not always possible. This has two problems: 1) It imposes an API on the constructor of subclasses (i.e. that they accept one parameter which would be an instance of the base class) 2) The builtin classes constructors doesn't even respect that, i.e. Hash.new({1 => 2}).has_key?(1) # => false -- Marc-Andr�� ---------------------------------------- Bug #6087: How should inherited methods deal with return values of their own subclass? https://bugs.ruby-lang.org/issues/6087 Author: Marc-Andre Lafortune Status: Open Priority: Normal Assignee: Yukihiro Matsumoto Category: core Target version: 2.0.0 ruby -v: trunk Just noticed that we still don't have a consistent way to handle return values: class A < Array end a = A.new a.flatten.class # => A a.rotate.class # => Array (a * 2).class # => A (a + a).class # => Array Some methods are even inconsistent depending on their arguments: a.slice!(0, 1).class # => A a.slice!(0..0).class # => A a.slice!(0, 0).class # => Array a.slice!(1, 0).class # => Array a.slice!(1..0).class # => Array Finally, there is currently no constructor nor hook called when making these new copies, so they are never properly constructed. Imagine this simplified class that relies on `@foo` holding a hash: class A < Array def initialize(*args) super @foo = {} end def initialize_copy(orig) super @foo = @foo.dup end end a = A.new.flatten a.class # => A a.instance_variable_get(:@foo) # => nil, should never happen I feel this violates object orientation. One solution is to always return the base class (Array/String/...). Another solution is to return the current subclass. To be object oriented, I feel we must do an actual `dup` of the object, including copying the instance variables, if any, and calling `initialize_copy`. Exceptions to this would be (1) explicit documentation, e.g. Array#to_a, or (2) methods inherited from a module (like Enumerable methods for Array). I'll be glad to fix these once there is a decision made on which way to go. -- http://bugs.ruby-lang.org/