# The dark side of inherited methods

**URL:** <https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676>\
**Category:** ruby-talk\
**Created:** [31 October 2010 22:30 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676 "2010-10-31T22:30:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tim\_R](https://avatars.discourse-cdn.com/v4/letter/t/ecc23a/32.png) [@Tim\_R](https://rubytalk.org/u/Tim_R)\
**Post date:** [31 October 2010 22:30 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/1 "2010-10-31T22:30:15Z")

</div>

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  
&nbsp;&nbsp;def initialize(\*arr)  
&nbsp;&nbsp;&nbsp;&nbsp;super(arr.flatten)  
&nbsp;&nbsp;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. If  
you look at the underlying C code that defines these methods the  
response makes sense. Collect! alters the object itself using the  
results from the block, while collect builds a new Array from the  
results of the block. But geesh, that means to have consistent  
behavior, I have to add the following (and worse, look through every  
other Array method to determine if the return value should be a vector  
rather than an array):

class Vector \< Array  
&nbsp;&nbsp;def collect(&blk)  
&nbsp;&nbsp;&nbsp;&nbsp;Vector.new(super) #gets the return from super and puts that  
back into a vector object  
&nbsp;&nbsp;end  
end

v = Vector.new(1,2,3) # =\> [1, 2, 3]  
v.class # =\> Vector  
v.collect{|item| item \* 3}.class # =\> Vector  
v.collect!{|item| item \* 3}.class # =\> Vector

When a method has the form of array -\> an\_array I want it to take a  
vector -\> a\_vector, but I get vector -\> array. 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?  
Thanks,  
Tim

---

<div class="post-metadata">

**Author:** ![Phil](https://avatars.discourse-cdn.com/v4/letter/p/e95f7d/32.png) [@Phil](https://rubytalk.org/u/Phil)\
**Post date:** [31 October 2010 22:42 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/2 "2010-10-31T22:42:14Z")

</div>

Define "consistent behavior". That #collect returns an Array is  
consistent with other, similar language constructs. The question is if  
you want an Array back, or want a Vector back from the operation you  
perform. Similarly, since you inherited the Array methods, Vector#join  
will behave exactly like Array#join.

That's pretty much the point of inheritance: Re-using a class's  
methods to make your own life easier by reducing the work you need to  
do, since most methods you expect to use are identical to what you  
need, and only need adaptation to your own needs (via encapsulation,  
or overriding, for example).

Maybe you have better success (i.e. less work), if you a) encapsulate  
similar calls into calls of your own and massage the operation that  
way, or b) you move one up in the inheritance change, and use  
Enumerable to inherit from. Most work will be c) create your class  
from scratch, and mix in Array or Enumerable.

TL;DR: Any class derived from another class will inherit its method.  
That's true for Ruby, as it is for Java or C#. It's pretty much the  
point of inheritance. 😉

> **···**
>
> On Sun, Oct 31, 2010 at 11:30 PM, timr \<timrandg@gmail.com\> wrote:
> 
> > 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. If  
> > you look at the underlying C code that defines these methods the  
> > response makes sense. Collect! alters the object itself using the  
> > results from the block, while collect builds a new Array from the  
> > results of the block. But geesh, that means to have consistent  
> > behavior, I have to add the following (and worse, look through every  
> > other Array method to determine if the return value should be a vector  
> > rather than an array):
> 
> --  
> Phillip Gawlowski
> 
> Though the folk I have met,  
> (Ah, how soon!) they forget  
> When I've moved on to some other place,  
> There may be one or two,  
> When I've played and passed through,  
> Who'll remember my song or my face.

---

<div class="post-metadata">

**Author:** ![JEG2](https://avatars.discourse-cdn.com/v4/letter/j/a183cd/32.png) [@JEG2](https://rubytalk.org/u/JEG2)\
**Post date:** [31 October 2010 23:49 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/3 "2010-10-31T23:49:36Z")

</div>

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  
&nbsp;&nbsp;def initialize(\*array)  
&nbsp;&nbsp;&nbsp;&nbsp;@array = array.flatten  
&nbsp;&nbsp;end  
&nbsp;&nbsp;  
&nbsp;&nbsp;def class  
&nbsp;&nbsp;&nbsp;&nbsp;::Vector  
&nbsp;&nbsp;end  
&nbsp;&nbsp;  
&nbsp;&nbsp;def method\_missing(meth, \*args, &blk)  
&nbsp;&nbsp;&nbsp;&nbsp;result = @array.send(meth, \*args, &blk)  
&nbsp;&nbsp;&nbsp;&nbsp;if result.object\_id == @array.object\_id  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self  
&nbsp;&nbsp;&nbsp;&nbsp;elsif result.class == ::Array  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.class.new(result)  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;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

> **···**
>
> 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)  
> > &nbsp;&nbsp;&nbsp;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?

---

<div class="post-metadata">

**Author:** ![Daniel\_Ribeiro](https://avatars.discourse-cdn.com/v4/letter/d/b5ac83/32.png) [@Daniel\_Ribeiro](https://rubytalk.org/u/Daniel_Ribeiro)\
**Post date:** [3 November 2010 20:34 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/4 "2010-11-03T20:34:49Z")

</div>

Scala solved this problem (which can viewed as a lack of the "uniform  
return type principle") on its collection library on version 2.8:  
[http://www.scala-lang.org/docu/files/collections-api/collections\_2.html](http://www.scala-lang.org/docu/files/collections-api/collections_2.html)

It used implicits arguments to do this. It is not a simple design, but  
it is quite general.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Dev\_Guy](https://avatars.discourse-cdn.com/v4/letter/d/ec9cab/32.png) [@Dev\_Guy](https://rubytalk.org/u/Dev_Guy)\
**Post date:** [31 October 2010 22:54 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/5 "2010-10-31T22:54:22Z")

</div>

I see how Vector is-a Array, I don't see how Array is-a Vector? I would consider collect and collect! to be inconsistent under this definition.

> **···**
>
> On 10-10-31 06:42 PM, Phillip Gawlowski wrote:
> 
> > On Sun, Oct 31, 2010 at 11:30 PM, timr\<timrandg@gmail.com\> wrote:
> > 
> > > 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. If  
> > > you look at the underlying C code that defines these methods the  
> > > response makes sense. Collect! alters the object itself using the  
> > > results from the block, while collect builds a new Array from the  
> > > results of the block. But geesh, that means to have consistent  
> > > behavior, I have to add the following (and worse, look through every  
> > > other Array method to determine if the return value should be a vector  
> > > rather than an array):
> > 
> > Define "consistent behavior". That #collect returns an Array is  
> > consistent with other, similar language constructs. The question is if  
> > you want an Array back, or want a Vector back from the operation you  
> > perform. Similarly, since you inherited the Array methods, Vector#join  
> > will behave exactly like Array#join.
> > 
> > That's pretty much the point of inheritance: Re-using a class's  
> > methods to make your own life easier by reducing the work you need to  
> > do, since most methods you expect to use are identical to what you  
> > need, and only need adaptation to your own needs (via encapsulation,  
> > or overriding, for example).
> > 
> > Maybe you have better success (i.e. less work), if you a) encapsulate  
> > similar calls into calls of your own and massage the operation that  
> > way, or b) you move one up in the inheritance change, and use  
> > Enumerable to inherit from. Most work will be c) create your class  
> > from scratch, and mix in Array or Enumerable.
> > 
> > TL;DR: Any class derived from another class will inherit its method.  
> > That's true for Ruby, as it is for Java or C#. It's pretty much the  
> > point of inheritance. 😉
> 
> --  
> Kind Regards,  
> Rajinder Yadav | DevMentor.org | Do Good! ~ Share Freely
> 
> GNU/Linux: 2.6.35-22-generic  
> Kubuntu x86\_64 10.10 | KDE 4.5.1  
> Ruby 1.9.2p0 | Rails 3.0.1

---

<div class="post-metadata">

**Author:** ![Tim\_R](https://avatars.discourse-cdn.com/v4/letter/t/ecc23a/32.png) [@Tim\_R](https://rubytalk.org/u/Tim_R)\
**Post date:** [1 November 2010 00:40 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/6 "2010-11-01T00:40:15Z")

</div>

It is a problem with inheritance and another reason why inheritance is  
almost never what we want.

Tim: Glad that I am not the only one who thinks inheritance has some  
holes.  
Tim: Note the corrected output from James Edward Gray II's response:

class Vector \< Object  
&nbsp;&nbsp;def initialize(\*array)  
&nbsp;&nbsp;&nbsp;&nbsp;@array = array.flatten  
&nbsp;&nbsp;end  
&nbsp;&nbsp;def class  
&nbsp;&nbsp;&nbsp;&nbsp;::Vector  
&nbsp;&nbsp;end  
&nbsp;&nbsp;def method\_missing(meth, \*args, &blk)  
&nbsp;&nbsp;&nbsp;&nbsp;result = @array.send(meth, \*args, &blk)  
&nbsp;&nbsp;&nbsp;&nbsp;if result.object\_id == @array.object\_id  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self  
&nbsp;&nbsp;&nbsp;&nbsp;elsif result.class == ::Array  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.class.new(result)  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end  
v = Vector.new(1,2,3) # =\> #\<Vector:0x10183c758  
@array=[1, 2, 3]\>  
v.class # =\> Vector  
v.collect { |item| item \* 3 }.class # =\> Vector  
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.

Tim: It actually runs fine in 1.8.7 just as you have it coded.  
Tim: However, I already blew my method\_missing to over-ride the  
mathematical operators (see below):  
Tim: But I get your approach and I will think about something along  
those lines. It could also work to set up a proxy class and use its  
method\_missing (since I already used Vector's method\_missing) to fix  
the type returned the way you did. But that means v -  
Vector.new(1,1,1); p\_of\_v = Proxy.new(v) every time I want to use a  
vector. Still not ideal.

class Vector \< Array  
&nbsp;&nbsp;undef :-, :+, :\*, :==

&nbsp;&nbsp;def initialize(\*arr)  
&nbsp;&nbsp;&nbsp;&nbsp;v = super(arr.flatten)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def to\_a  
&nbsp;&nbsp;&nbsp;&nbsp;Array.new(self)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def &(arg)  
&nbsp;&nbsp;&nbsp;&nbsp;Vector.new(super)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def |(arg)  
&nbsp;&nbsp;&nbsp;&nbsp;Vector.new(super)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def collect(&blk)  
&nbsp;&nbsp;&nbsp;&nbsp;Vector.new(super)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def select(&blk)  
&nbsp;&nbsp;&nbsp;&nbsp;Vector.new(super)  
&nbsp;&nbsp;end

&nbsp;&nbsp;def method\_missing(meth, arg)  
&nbsp;&nbsp;&nbsp;&nbsp;arg.class == Vector ? a2 = arg : a2 = Vector.new(arg)  
&nbsp;&nbsp;&nbsp;&nbsp;long, short = [self, a2].sort{|s,b| b.length \<=\> s.length}  
&nbsp;&nbsp;&nbsp;&nbsp;empty\_collection = Array.new(long.length)

&nbsp;&nbsp;&nbsp;&nbsp;arr\_result = empty\_collection.each\_with\_index.map do |item, ind|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self[ind%self.length] == nil || a2[ind%a2.length] == nil  
#allow nils to be mathematically processed  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self[ind%self.length].send(meth, a2[ind%a2.length])  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;Vector.new(arr\_result)  
&nbsp;&nbsp;end  
end

Example Usage:  
a = Vector.new([1,2,1,10])  
b = Vector.new([2,5,1,7])  
a - b # =\> [-1, -3, 0, 3]  
a.uniq.class # =\> Vector  
(a | b) # =\> [1, 2, 10, 5, 7]  
(a | b).class # =\> Vector

---

<div class="post-metadata">

**Author:** ![Forum](https://avatars.discourse-cdn.com/v4/letter/f/43a26b/32.png) [@Forum](https://rubytalk.org/u/Forum)\
**Post date:** [1 November 2010 19:51 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/7 "2010-11-01T19:51:51Z")

</div>

\<snip\>

> It is a problem with inheritance and another reason why inheritance is almost never what we want.

Completely agree with this. Apart of the code you suggested I would  
like to tackle the problem on a conceptional level. Enumerable#map  
returns arrays Period. What OP might want to do is something like this

module Sequence  
&nbsp;&nbsp;include Enumerable  
&nbsp;&nbsp;# A sequence is defined by  
&nbsp;&nbsp;# (i) How to traverse it  
&nbsp;&nbsp;# def each &blk  
&nbsp;&nbsp;# making sure that blk is called with exactly all elements of the  
sequence in the  
&nbsp;&nbsp;# predefined order  
&nbsp;&nbsp;# (ii) How to append elements to it  
&nbsp;&nbsp;# def add new\_element  
&nbsp;&nbsp;# creating a new sequence (or modifying in place)  
&nbsp;&nbsp;def map &blk  
&nbsp;&nbsp;&nbsp;&nbsp;inject(self.class.new) do | result, ele |  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.add blk.( ele )  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end # module Sequence

If OP had had this available the delegation would have worked quite well.

class Vector  
&nbsp;&nbsp;&nbsp;include Sequence  
&nbsp;&nbsp;&nbsp;def each; # as he needs (must yield all elements)  
&nbsp;&nbsp;&nbsp;def add; # as he needs (must return a Sequence)

No inheritance and yet quite some effective decomposition 😛

HTH  
R.

> **···**
>
> On Mon, Nov 1, 2010 at 12:49 AM, James Edward Gray II \<james@graysoftinc.com\> wrote:
> 
> > On Oct 31, 2010, at 5:30 PM, timr wrote:
> 
> --  
> There are worse things than having people misunderstand your work. A  
> worse danger is that you will yourself misunderstand your work.  
> -- Paul Graham

---

<div class="post-metadata">

**Author:** ![Daniel\_Berger2](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/daniel_berger2/32/2243_2.png) [@Daniel\_Berger2](https://rubytalk.org/u/Daniel_Berger2)\
**Post date:** [1 November 2010 21:32 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/8 "2010-11-01T21:32:54Z")

</div>

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

> **···**
>
> On Oct 31, 5:49 pm, James Edward Gray II \<ja...@graysoftinc.com\> 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.

---

<div class="post-metadata">

**Author:** ![Tony\_Arcieri4](https://avatars.discourse-cdn.com/v4/letter/t/c77e96/32.png) [@Tony\_Arcieri4](https://rubytalk.org/u/Tony_Arcieri4)\
**Post date:** [2 November 2010 03:29 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/9 "2010-11-02T03:29:48Z")

</div>

That's a pretty extreme position to take. Inheritance is an indispensable  
tool. That said, I will agree that "is a" relationships come up far less  
frequently than 'has a" relationships.

I would say that it would make far more sense to create a Vector class which  
"has a"(n) array, and make the Vector an Enumerable. Of course, what makes  
even more sense is to use the Vector class provided by "require 'matrix'"

> **···**
>
> On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II \<james@graysoftinc.com \> wrote:
> 
> > It is a problem with inheritance and another reason why inheritance is  
> > almost never what we want.
> 
> --  
> Tony Arcieri  
> Medioh! A Kudelski Brand

---

<div class="post-metadata">

**Author:** ![Phil](https://avatars.discourse-cdn.com/v4/letter/p/e95f7d/32.png) [@Phil](https://rubytalk.org/u/Phil)\
**Post date:** [31 October 2010 23:00 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/10 "2010-10-31T23:00:49Z")

</div>

Array#collect returns a new Array. Array#collect! returns the existing  
Array. Thus, Vector#collect returns a new Array, and Vector#collect!  
returns the existing Vector. Bang-methods operate on the object  
itself, and return the modified object, instead of creating a new  
object containing the result of the operation the non-Bang-method  
performed.

The behavior is consistent with how methods with and without Bang operate.

> **···**
>
> On Sun, Oct 31, 2010 at 11:54 PM, Rajinder Yadav \<devguy.ca@gmail.com\> wrote:
> 
> > I see how Vector is-a Array, I don't see how Array is-a Vector? I would  
> > consider collect and collect! to be inconsistent under this definition.
> 
> --  
> Phillip Gawlowski
> 
> Though the folk I have met,  
> (Ah, how soon!) they forget  
> When I've moved on to some other place,  
> There may be one or two,  
> When I've played and passed through,  
> Who'll remember my song or my face.

---

<div class="post-metadata">

**Author:** ![JEG2](https://avatars.discourse-cdn.com/v4/letter/j/a183cd/32.png) [@JEG2](https://rubytalk.org/u/JEG2)\
**Post date:** [1 November 2010 21:55 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/11 "2010-11-01T21:55:55Z")

</div>

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

> **···**
>
> On Nov 1, 2010, at 4:32 PM, Daniel Berger wrote:
> 
> > On Oct 31, 5:49 pm, James Edward Gray II \<ja...@graysoftinc.com\> \> 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)  
> > > > &nbsp;&nbsp;&nbsp;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  
> > > &nbsp;&nbsp;def initialize(\*array)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;@array = array.flatten  
> > > &nbsp;&nbsp;end
> > > 
> > > &nbsp;&nbsp;def class  
> > > &nbsp;&nbsp;&nbsp;&nbsp;::Vector  
> > > &nbsp;&nbsp;end
> > > 
> > > &nbsp;&nbsp;def method\_missing(meth, \*args, &blk)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;result = @array.send(meth, \*args, &blk)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;if result.object\_id == @array.object\_id  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self  
> > > &nbsp;&nbsp;&nbsp;&nbsp;elsif result.class == ::Array  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.class.new(result)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;else  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;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.

---

<div class="post-metadata">

**Author:** ![Forum](https://avatars.discourse-cdn.com/v4/letter/f/43a26b/32.png) [@Forum](https://rubytalk.org/u/Forum)\
**Post date:** [2 November 2010 08:01 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/12 "2010-11-02T08:01:55Z")

</div>

> > It is a problem with inheritance and another reason why inheritance is  
> > almost never what we want.

I cannot speak for Edward but would like to defend my (+1) on this.  
Actually there is nothing to defend because I did not read correctly  
(good :(). I read inheritance from a "core class", which was not  
written. And then I continued to read text that was not there:  
"inheritance from a core class using delegation to #each".  
That said I should probably apologize :P, so I do. But I guess that is  
where the "problem" comes from.  
Cheers  
Robert

> **···**
>
> --  
> There are worse things than having people misunderstand your work. A  
> worse danger is that you will yourself misunderstand your work.  
> -- Paul Graham

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [2 November 2010 09:31 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/13 "2010-11-02T09:31:56Z")

</div>

> > It is a problem with inheritance and another reason why inheritance is  
> > almost never what we want.
> 
> That's a pretty extreme position to take. Inheritance is an indispensable  
> tool. That said, I will agree that "is a" relationships come up far less  
> frequently than 'has a" relationships.

I believe this is what James wanted to stress: inheritance is used far  
too often for purposes where it's not appropriate. A real is\_a  
relationship is pretty rare yet many people use inheritance,  
especially with core / std lib classes as parents which almost always  
is a code smell.

Side note: there are languages such as Eiffel and C++ which have  
support for implementation inheritance (i.e. the interface changes  
incompatibly from super class to sub class) and in those languages  
inheritance can be used more often than in language which lack these  
features (e.g. Java).

> I would say that it would make far more sense to create a Vector class which  
> "has a"(n) array, and make the Vector an Enumerable. Of course, what makes  
> even more sense is to use the Vector class provided by "require 'matrix'"

Absolutely.

Kind regards

robert

> **···**
>
> On Tue, Nov 2, 2010 at 4:29 AM, Tony Arcieri \<tony.arcieri@medioh.com\> wrote:
> 
> > On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II \<james@graysoftinc.com \>\> wrote:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![JEG2](https://avatars.discourse-cdn.com/v4/letter/j/a183cd/32.png) [@JEG2](https://rubytalk.org/u/JEG2)\
**Post date:** [2 November 2010 16:19 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/14 "2010-11-02T16:19:19Z")

</div>

There have been a lot of books written about the evils of inheritance. It's mentioned on the Wikipedia page for inheritance. I thought it was pretty much a given at this point.

Of course, there are various forms of inheritance. It's "implementation inheritance" that's the main problem.

Design Patterns could also be called Ways to Avoid (Implementation) Inheritance, I think. I find that it's even easier and more desirable to avoid inheritance with a language as dynamic as Ruby.

Of course, inheritance has it's place and uses but I feel it's definitely overused.

James Edward Gray II

> **···**
>
> On Nov 1, 2010, at 10:29 PM, Tony Arcieri wrote:
> 
> > On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II \<james@graysoftinc.com \>\> wrote:
> > 
> > > It is a problem with inheritance and another reason why inheritance is  
> > > almost never what we want.
> > 
> > That's a pretty extreme position to take. Inheritance is an indispensable tool.

---

<div class="post-metadata">

**Author:** ![Dev\_Guy](https://avatars.discourse-cdn.com/v4/letter/d/ec9cab/32.png) [@Dev\_Guy](https://rubytalk.org/u/Dev_Guy)\
**Post date:** [31 October 2010 23:58 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/15 "2010-10-31T23:58:49Z")

</div>

Thanks Phillip, yes I agree with respect to the implementation, i get it. was mulling that over after i hit send =P

> **···**
>
> On 10-10-31 07:00 PM, Phillip Gawlowski wrote:
> 
> > On Sun, Oct 31, 2010 at 11:54 PM, Rajinder Yadav\<devguy.ca@gmail.com\> wrote:
> > 
> > > I see how Vector is-a Array, I don't see how Array is-a Vector? I would  
> > > consider collect and collect! to be inconsistent under this definition.
> > 
> > Array#collect returns a new Array. Array#collect! returns the existing  
> > Array. Thus, Vector#collect returns a new Array, and Vector#collect!  
> > returns the existing Vector. Bang-methods operate on the object  
> > itself, and return the modified object, instead of creating a new  
> > object containing the result of the operation the non-Bang-method  
> > performed.
> > 
> > The behavior is consistent with how methods with and without Bang operate.
> 
> --  
> Kind Regards,  
> Rajinder Yadav | DevMentor.org | Do Good! ~ Share Freely
> 
> GNU/Linux: 2.6.35-22-generic  
> Kubuntu x86\_64 10.10 | KDE 4.5.1  
> Ruby 1.9.2p0 | Rails 3.0.1

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [1 November 2010 22:20 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/16 "2010-11-01T22:20:21Z")

</div>

> My first reaction when I saw the original code was, "Eeep, inheriting  
> from a core class."

+1 (me too)

> I guess we both have some fear to get past. 🙂

Well, I don't think it is a question of fear. 🙂

Cheers

&nbsp;&nbsp;robert

> **···**
>
> On 01.11.2010 22:55, James Edward Gray II wrote:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![7rans](https://avatars.discourse-cdn.com/v4/letter/7/a8b319/32.png) [@7rans](https://rubytalk.org/u/7rans)\
**Post date:** [2 November 2010 16:37 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/17 "2010-11-02T16:37:27Z")

</div>

Indeed, I think inheritance gets a really bad rap in Ruby b/c Ruby's  
base classes and inheritance system are so poorly designed to handle  
it.

The other day I was talking to my Father, a Cobol programmer from back  
in the day, and he was telling me that when he retired, OOP was just  
starting to get hyped. He was quite interested in it at the time and  
then rattled off some of the advantages he remembered it was to bring  
to the field. Inheritance for code reuse was high on the list and  
related to that, one point eally struck me -- instead of versioning  
code as we have become accustomed, the idea was to subclass the  
original class and implement changes in the subclass. Using some sort  
of class name referencing scheme you could use any version. It sort of  
reminded me of database migrations.

I imagined is something like:

&nbsp;&nbsp;class Foo1  
&nbsp;&nbsp;&nbsp;&nbsp;..  
&nbsp;&nbsp;end

&nbsp;&nbsp;class Foo2 \< Foo1  
&nbsp;&nbsp;&nbsp;&nbsp;...  
&nbsp;&nbsp;end

&nbsp;&nbsp;#pick a version  
&nbsp;&nbsp;Foo = Foo2

Sadly, I had to inform him that OOP did not quite prove to be the  
godsend everyone originally thought it might be.

> **···**
>
> On Nov 2, 5:31 am, Robert Klemme \<shortcut...@googlemail.com\> wrote:
> 
> > On Tue, Nov 2, 2010 at 4:29 AM, Tony Arcieri \<tony.arci...@medioh.com\> wrote:  
> > \> On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II \<ja...@graysoftinc.com \> \>\> wrote:
> > 
> > \>\> It is a problem with inheritance and another reason why inheritance is  
> > \>\> almost never what we want.
> > 
> > \> That's a pretty extreme position to take. Inheritance is an indispensable  
> > \> tool. That said, I will agree that "is a" relationships come up far less  
> > \> frequently than 'has a" relationships.
> > 
> > I believe this is what James wanted to stress: inheritance is used far  
> > too often for purposes where it's not appropriate. A real is\_a  
> > relationship is pretty rare yet many people use inheritance,  
> > especially with core / std lib classes as parents which almost always  
> > is a code smell.
> > 
> > Side note: there are languages such as Eiffel and C++ which have  
> > support for implementation inheritance (i.e. the interface changes  
> > incompatibly from super class to sub class) and in those languages  
> > inheritance can be used more often than in language which lack these  
> > features (e.g. Java).

---

<div class="post-metadata">

**Author:** ![Josh\_Cheek](https://avatars.discourse-cdn.com/v4/letter/j/e79b87/32.png) [@Josh\_Cheek](https://rubytalk.org/u/Josh_Cheek)\
**Post date:** [2 November 2010 17:02 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/18 "2010-11-02T17:02:24Z")

</div>

Can you give some examples of where it has its place? I have been trying to  
think of one, and can't. I realized the only time I ever subclass anything  
is ActiveRecord::Base (and I'm not really sure what that offers over  
modules, DataMapper uses modules, for example).

> **···**
>
> On Tue, Nov 2, 2010 at 11:19 AM, James Edward Gray II \<james@graysoftinc.com \> wrote:
> 
> > Of course, inheritance has it's place and uses but I feel it's definitely  
> > overused.

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [2 November 2010 17:40 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/19 "2010-11-02T17:40:14Z")

</div>

> > > > It is a problem with inheritance and another reason why inheritance is  
> > > > almost never what we want.
> > 
> > > That's a pretty extreme position to take. Inheritance is an indispensable  
> > > tool. That said, I will agree that "is a" relationships come up far less  
> > > frequently than 'has a" relationships.
> > 
> > I believe this is what James wanted to stress: inheritance is used far  
> > too often for purposes where it's not appropriate. A real is\_a  
> > relationship is pretty rare yet many people use inheritance,  
> > especially with core / std lib classes as parents which almost always  
> > is a code smell.
> > 
> > Side note: there are languages such as Eiffel and C++ which have  
> > support for implementation inheritance (i.e. the interface changes  
> > incompatibly from super class to sub class) and in those languages  
> > inheritance can be used more often than in language which lack these  
> > features (e.g. Java).
> 
> Indeed, I think inheritance gets a really bad rap in Ruby b/c Ruby's  
> base classes and inheritance system are so poorly designed to handle  
> it.

I would not subscribe to that. Although Bertrand Meyer is a big fan of implementation inheritance I am not yet convinced that it is such a good idea so often. Of course, there are always uses for any technique present, but I find the "is a" relationship interpretation of inheritance so clear and obvious that I somehow feel bad about polluting inheritance with other uses. I cannot really put forward a more concrete argument or even back this up by some hard (business) numbers, but a world in which "A inherits B" \<=\> "A is a B" is so much simpler. And in Ruby, whenever you need implementation inheritance you can use a mixin module. Enumerable is a very good example for that.

> The other day I was talking to my Father, a Cobol programmer from back  
> in the day, and he was telling me that when he retired, OOP was just  
> starting to get hyped. He was quite interested in it at the time and  
> then rattled off some of the advantages he remembered it was to bring  
> to the field. Inheritance for code reuse was high on the list and

Well, there are other forms of code reuse - even in procedural languages. It's not that you \_need\_ inheritance to have code reuse. I would even go as far as to claim that it is more difficult to implement classes intended solely for implementation inheritance than classes which implement a particular real world concept and which are only inherited if "is a" is needed. I say this because a class intended for implementation inheritance needs other criteria for including functionality than a class which implements a particular concept.

> related to that, one point eally struck me -- instead of versioning  
> code as we have become accustomed, the idea was to subclass the  
> original class and implement changes in the subclass. Using some sort  
> of class name referencing scheme you could use any version.

That does not sound like a, um, proper application of inheritance to me. It might be useful to do it that way in some rare conditions but I would not promote this as a big feature of inheritance.

> Sadly, I had to inform him that OOP did not quite prove to be the  
> godsend everyone originally thought it might be.

Well, silver bullets - if you know one, you know them all. 🙂

Btw, I find that we have this type of discussion far too seldom here nowadays and I imagine that we did that more often earlier on. But that is totally subjective.

Cheers

&nbsp;&nbsp;robert

> **···**
>
> On 02.11.2010 17:37, Intransition wrote:
> 
> > On Nov 2, 5:31 am, Robert Klemme\<shortcut...@googlemail.com\> wrote:
> > 
> > > On Tue, Nov 2, 2010 at 4:29 AM, Tony Arcieri\<tony.arci...@medioh.com\> wrote:
> > > 
> > > > On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II\<ja...@graysoftinc.com \>\>\>\> wrote:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://avatars.discourse-cdn.com/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://rubytalk.org/u/Joel_VanderWerf)\
**Post date:** [2 November 2010 18:04 UTC](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676/20 "2010-11-02T18:04:37Z")

</div>

The shortest example that occurs to me:

class A \< Struct.new :x, :y, :z  
&nbsp;&nbsp;&nbsp;def length  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math.sqrt(x\*\*2 + y\*\*2 + z\*\*2)  
&nbsp;&nbsp;&nbsp;end  
end

That only saves a couple of keystrokes compared to:

A = Struct.new :x, :y, :z  
class A  
...

but it's cleaner IMO. Also, it allows you to do this:

&nbsp;&nbsp;&nbsp;def x=(new\_x)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if new\_x \> 100  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super  
&nbsp;&nbsp;&nbsp;end

In the "A=Struct.new" approach, you have to muck around with alias to get the same effect.

> **···**
>
> On 11/02/2010 10:02 AM, Josh Cheek wrote:
> 
> > On Tue, Nov 2, 2010 at 11:19 AM, James Edward Gray II\<james@graysoftinc.com \>\> wrote:
> > 
> > > Of course, inheritance has it's place and uses but I feel it's definitely  
> > > overused.
> > 
> > Can you give some examples of where it has its place? I have been trying to  
> > think of one, and can't. I realized the only time I ever subclass anything  
> > is ActiveRecord::Base (and I'm not really sure what that offers over  
> > modules, DataMapper uses modules, for example).

[Next page](https://rubytalk.org/t/the-dark-side-of-inherited-methods/60676.md?page=2)
