From: James Edward Gray II Date: 2010-11-01T08:49:36+09:00 Subject: Re: the dark side of inherited methods 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. James Edward Gray II