# Composition/inheritance/subclassing standard lib classes

**URL:** <https://www.ruby-forum.com/t/composition-inheritance-subclassing-standard-lib-classes/122935>\
**Category:** Ruby\
**Created:** [December 12, 2007, 9:41pm UTC](https://www.ruby-forum.com/t/composition-inheritance-subclassing-standard-lib-classes/122935 "2007-12-12T21:41:33Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![bobt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e8cbc/32.png) [@bobt](https://www.ruby-forum.com/u/bobt)\
**Post date:** [December 12, 2007, 9:41pm UTC](https://www.ruby-forum.com/t/composition-inheritance-subclassing-standard-lib-classes/122935/1 "2007-12-12T21:41:33Z")

</div>

Hi,

An old ruby quiz (#24) deals with a game of poker, and there’s a  
“Deck” class in a couple of solutions. These classes have an array of  
Card objects.

Similarly, in an example in the Prag porgrammers guide, a SongList  
class has an array, which is a list of Song objects.

To me, it would seem more natural if “Deck” and “SongList” were  
subclasses of Array, and added Cards/Songs to self. Does anybody have  
an explanation or a good link talking about the merits of these  
different approaches?

thanks,

bob

---

<div class="post-metadata">

**Author:** ![bobt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e8cbc/32.png) [@bobt](https://www.ruby-forum.com/u/bobt)\
**Post date:** [December 13, 2007, 1:40pm UTC](https://www.ruby-forum.com/t/composition-inheritance-subclassing-standard-lib-classes/122935/2 "2007-12-13T13:40:52Z")

</div>

> entire Smalltalk Collection Hierarchy in one single Class! And so, a  
> inheriting from it, through the use of metaprogramming, Delegator,
> 
> An alternate approach if you don’t want a specialized Domain Object  
> but rather a specialized generic Collection is described here:  
> [http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/](http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/).  
> The basic idea is: copy the Array Class (remember, Classes are just  
> Objects, too!), remove the methods that you don’t want, et voilà,  
> there is a List or a Stack or a Queue which isn’t a subclass of Array  
> but actually “inherits” its behaviour.
> 
> jwm

Hi,

Thanks for such a detailed reply. There are some concepts there that  
are new to me (delegator/forwardable). I love the way that the Array  
class has so many useful built in methods, but i can see why you don’t  
want an interface that big for every class.

> [http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/](http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/).

In this link that you posted, i don’t understand the Array.extract  
syntax? where is this “extract” method coming from?

thanks again,

bob

---

<div class="post-metadata">

**Author:** ![bobt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e8cbc/32.png) [@bobt](https://www.ruby-forum.com/u/bobt)\
**Post date:** [December 13, 2007, 4:16am UTC](https://www.ruby-forum.com/t/composition-inheritance-subclassing-standard-lib-classes/122935/3 "2007-12-13T04:16:16Z")

</div>

Hi Bob!

removed\_email\_address@domain.invalid wrote:

> different approaches?  
> The way I see it, there’s two reasons: a more metaphysical design  
> reason and a more practical reason. Let’s start with the metaphysical  
> one.

In Object-Oriented Design we try to model concepts and entities from  
the real world with Objects in our programming language. There are  
correspondences between our Objects and our concepts as well as  
between the relationships between our Objects and the relationships  
between our concepts. In particular: an instance-of relationship  
between an Object and a Class as well as a subclass-of relationship  
between a Class and another Class correspond to an is-a relationship  
between concepts or entities.

So, to add yet another cats and dogs and cars example to the huge  
existing pile …

class Mammal; end  
class Dog \< Mammal; end  
lassie = Dog.new

Now Lassie is an instance of Dog, and Dog is a subclass of Mammal. In  
the real world this corresponds to “Lassie is a Dog” and “Every Dog is  
a Mammal”. If you can get in front of a mirror, look yourself in the  
eye and say this with a straight face, then making Lassie an instance  
of Dog and Dog a subclass of Mammal is likely correct, otherwise you  
should think twice.

Now, can you say with a straight face that “Every Deck of Cards is an  
Array”? Maybe not.

So, on to reason number two, the practical reason: Arrays in Ruby are  
an unwieldy beast. Traditionally, Collections have been very hard to  
model in classical object-oriented programming languages. Is it  
Array \< OrderedCollectionWithDuplicateEntries \<  
CollectionWithDuplicateEntries  
or Array \< OrderedCollectionWithDuplicateEntries \< OrderedCollection?  
There are many ways to solve this, Multiple Inheritance or Traits for  
example, but Ruby has found a rather elegant solution: just squish the  
entire Smalltalk Collection Hierarchy in one single Class! And so, a  
Ruby Array is not only an Array but also a List (first), a Queue  
(shift/unshift), a Stack (push/pop), a Vector, a Bag, a Set (uniq, |,  
&), a Tuple and even a Matrix (transpose)!

This power comes with a cost, though: 71 public instance methods on  
Array (not counting the methods inherited from Object or mixed in from  
Enumerable)! Do you really want to have all of that on your Deck of  
Cards? What does “transpose” mean in the context of a SongList?

Ruby makes it _very_ easy to delegate to an Array instead of  
inheriting from it, through the use of metaprogramming, Delegator,  
Forwardable and friends. It also makes it easy to keep the Array “look  
and feel” on your own objects, because a lot of what looks like Array  
specific operators are actually just methods (e.g. [], []=, \<\<) that  
you can just as well implement on your own class. And thirdly, several  
useful methods aren’t actually methods of the Array Class but of the  
Enumerable Module that you can mix in into your own class.

So, by delegating a couple of methods to an Array and mixing in  
Enumerable you get something that looks an awful lot like an Array but  
is actually a Domain Object custom-tailored to your specific needs.

An alternate approach if you don’t want a specialized Domain Object  
but rather a specialized generic Collection is described here:  
[http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/](http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/).  
The basic idea is: copy the Array Class (remember, Classes are just  
Objects, too!), remove the methods that you don’t want, et  
voilà,there is a List or a Stack or a Queue which isn’t a subclass of Array  
but actually “inherits” its behaviour.

jwm

---

<div class="post-metadata">

**Author:** ![bobt](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e8cbc/32.png) [@bobt](https://www.ruby-forum.com/u/bobt)\
**Post date:** [January 25, 2008, 1:30pm UTC](https://www.ruby-forum.com/t/composition-inheritance-subclassing-standard-lib-classes/122935/4 "2008-01-25T13:30:54Z")

</div>

Hi!

Sorry for the late reply.

Paul Nulty wrote:

> > An alternate approach if you don’t want a specialized Domain Object  
> > but rather a specialized generic Collection is described here:  
> > [http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/](http://Rubylution.Ping.De/articles/2005/12/21/rubys-rich-array-api/).  
> > The basic idea is: copy the Array Class (remember, Classes are just  
> > Objects, too!), remove the methods that you don’t want, et voilà,  
> > there is a List or a Stack or a Queue which isn’t a subclass of Array  
> > but actually “inherits” its behaviour.  
> > In this link that you posted, i don’t understand the Array.extract  
> > syntax? where is this “extract” method coming from?

It’s a method that the author of said article wrote to implement  
exactly what I described: copying a class and deleting all methods not  
in the “extract” list. (The method actually has a couple of more  
tricks up its sleeve.) The implementation is actually linked in the  
article: [http://Rubylution.Ping.De/files/extract.rb](http://Rubylution.Ping.De/files/extract.rb).

jwm
