From: Daniel Berger Date: 2010-11-02T06:32:54+09:00 Subject: Re: the dark side of inherited methods On Oct 31, 5:49 pm, James Edward Gray II wrote: > On Oct 31, 2010, at 5:30 PM, timr wrote: > > > > > > > > > > > Let's say I want to make a new class, Vector (that will function, > > eventually, like R vectors for mathematical operations), and I write > > this: > > > class Vector < Array > >  def initialize(*arr) > >    super(arr.flatten) > >  end > > end > > > v = Vector.new(1,2,3) # => [1, 2, 3] > > v.class # => Vector > > v.collect{|item| item * 3}.class # => Array > > v.collect!{|item| item * 3}.class # => Vector > > > I noticed that I inherited the Array#collect and Array#collect! > > methods. Yeah for inheritance! But then look at the returned classes. > > Array#collect returns and array. Array.collect! returns a Vector. > > Is there a simple way to fix this for all similar methods? Or do I just have to live with the dark side of inherited methods? > > It is a problem with inheritance and another reason why inheritance is almost never what we want.  Luckily, this is Ruby where anything is possible: > > class Vector < BasicObject >   def initialize(*array) >     @array = array.flatten >   end > >   def class >     ::Vector >   end > >   def method_missing(meth, *args, &blk) >     result = @array.send(meth, *args, &blk) >     if result.object_id == @array.object_id >       self >     elsif result.class == ::Array >       self.class.new(result) >     else >       result >     end >   end > end > v = Vector.new(1,2,3)                # => [1, 2, 3] > v.class                              # => Vector > v.collect { |item| item * 3 }.class  # => Array > v.collect!{ |item| item * 3 }.class  # => Vector > > That's a solution for Ruby 1.9, but a similar trick is possible with 1.8 using a touch more code.  It's probably not perfect yet, but you get the idea. Eeep, method_missing. I was thinking this might be accomplished via some sort of AOP. I looked at AspectR and Aquarium but couldn't make it work. Maybe that's the wrong approach, though. Regards, Dan