From: James Edward Gray II Date: 2010-11-02T06:55:55+09:00 Subject: Re: the dark side of inherited methods On Nov 1, 2010, at 4:32 PM, Daniel Berger wrote: > 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. My first reaction when I saw the original code was, "Eeep, inheriting from a core class." I guess we both have some fear to get past. :) James Edward Gray II