From: Robert Klemme Date: 2010-11-04T21:37:39+09:00 Subject: Re: the dark side of inherited methods On Thu, Nov 4, 2010 at 10:55 AM, Klaus Stein wrote: > Robert Klemme wrote: >> But this does not solve the major issue that you change the interface. >>  Currently there is a ton of code around that works with the >> assumption (explicit or implicit) that #select returns an Array.  I >> would not dare judge how much code will be broken if we change the >> default behavior. > > This is why I would not want this as _default_ behavior. I would expect > select, reject etc return an Array as it is now. But if the class including > Enumerable provides a _special_ MyCollection::enumNew method it would be > used instead. > > So something like > > module Enumerable >  def select >    r = (self.class.enumNew(self) rescue []) >    # [ rest of the select code ] >  end > end > > would do. This should not break old code. It will, because classes can be modified in Ruby. require 'set' class Set def self.enum_new(other_set) new end end require 'a_library_that_uses_set' ... x = a_set.select {|x| x > 0} assert { Array === x } # boom! Again, global state (in this case a method in class Set) bytes. My suggested approach with providing the class as argument is better IMHO because - It is more flexible (at one time you can map an Array to a Set, another time to an Array etc.). - It does not break old code (see above). Actually you do not want to determine the return type of Set#map *globally* but rather per *use*. > I am not sure how to implement this best, as creating an empty collection > and adding elements by << ma be not the most efficient way to go. There is no other way because you do not know beforehand whether all or only part of the elements of the current collection go into the new one. > (please note that MyCollection.enumNew takes the original object as >  parameter to be able to copy other instance variables etc) I noticed that but this is useless without knowing what the copy will be used for. Enumerable#map and #select have vastly differing semantics! Cheers robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/