Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > composition/inheritance/subclassing standard lib classes

Reply
Thread Tools

composition/inheritance/subclassing standard lib classes

 
 
bobterwillinger@gmail.com
Guest
Posts: n/a
 
      12-12-2007
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
 
Reply With Quote
 
 
 
 
Jörg W Mittag
Guest
Posts: n/a
 
      12-13-2007
Hi Bob!

http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> 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?


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/>.
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
 
Reply With Quote
 
 
 
 
Paul Nulty
Guest
Posts: n/a
 
      12-13-2007

> 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/>.
> 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/>.


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

thanks again,

bob
 
Reply With Quote
 
Jörg W Mittag
Guest
Posts: n/a
 
      01-25-2008
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/>.
>> 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>.

jwm
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
difference between libboost_regex-mt-gd-1_33_1.lib and boost_regex-mt-gd-1_33_1.lib ideal.black@gmail.com C++ 3 09-30-2007 06:54 AM
how to debug this error? /usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../lib/crt1.o Durduran C Programming 10 07-30-2007 09:03 PM
Need odbc32.lib odbccp32.lib Praetorian C++ 1 04-20-2006 07:14 PM
Diff betw common/lib and shared/lib in Tomcat James Yong Java 0 09-12-2005 02:36 AM
Standard Lib To Use New-Style Classes? John Abel Python 1 09-06-2003 04:07 PM



Advertisments