[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

The Case for Multiple-Inheritance

Trans

10/5/2007 9:07:00 PM

So I working on little lib that's ripe for an adapter pattern, when I
see quite clearly that I have a bit of a dilemma. I have two clear
inheritance hierarchies converging. I want to create a
LinuxVideoPlayerApplication subclass, but it needs to inherit from
both VideoPlayerApplication and LinuxApplication.

class VideoPlayerApplication < Application


class LinuxApplication < Applicaiton

Oh no!

class LinuxVideoPlayerApplication < VideoPlayerApplication

or

class LinuxVideoPlayerApplication < LinuxApplication

Ruby forces me make a choice. Which is "more real" I guess is it's
demand. But the choice is contrived. Both apply, and Ruby's strict
single-inheritance philosophy does nothing for me in the end except
make my life more complicated. One way or the other I am going to get
both behaviors in there. Period.

So as things are, I'm stuck with making one of them a module instead
of a class. But then I loose metaclass inheritance, which can be a
real pain sometimes. I become inclined to make them both modules and
use separate meta-modules if need be, to keep things nicely symmetric.
But really, why should I have to make such a fuss? Why do I have to
draw so many abstract distinctions when there is no such thing in my
actual model?

I think it would be a good idea to really give some deep consideration
as to why modules and classes are distinct in Ruby. It's clear from
Ruby's source that the distinction is self-inflicted to begin with.
Why? Are we really gaining anything by the distinction, or are we just
making things harder for ourselves w/o necessarily realizing it,
simply because that's the "philosophy".

Food for thought,
T.


94 Answers

Austin Ziegler

10/5/2007 10:14:00 PM

0

On 10/5/07, Trans <transfire@gmail.com> wrote:
> So I working on little lib that's ripe for an adapter pattern, when I
> see quite clearly that I have a bit of a dilemma. I have two clear
> inheritance hierarchies converging. I want to create a
> LinuxVideoPlayerApplication subclass, but it needs to inherit from
> both VideoPlayerApplication and LinuxApplication.

I think that you've got a problem here, and it won't be solved with MI.
You need to reapproach the issue. I have yet to find a time when MI
makes sense even in C++.

> class VideoPlayerApplication < Application
> class LinuxApplication < Application
>
> Oh no!
>
> class LinuxVideoPlayerApplication < VideoPlayerApplication
> or
> class LinuxVideoPlayerApplication < LinuxApplication

Frankly, I don't think you've got a good design here, without seeing
anything else.

A LinuxApplication isn't sensible. What makes a LinuxApplication
different from a GenericApplication or from a WindowsApplication? In
other words, I think that you've set yourself up for the dichotomy by
not considering this the right way.

Think of it in terms of aspects. What are the aspects that make an
application a Linux application? How can you pull those in cleanly?


> Ruby forces me make a choice. Which is "more real" I guess is it's
> demand. But the choice is contrived. Both apply, and Ruby's strict
> single-inheritance philosophy does nothing for me in the end except
> make my life more complicated. One way or the other I am going to get
> both behaviors in there. Period.

That's fine, but nothing you've written suggests that MI is a good idea.

> So as things are, I'm stuck with making one of them a module instead
> of a class.

Why?

Avoid inheritance when you don't need it -- and you need it a lot less
than you think. Composition is usually a better approach than
inheritance.

> But then I loose metaclass inheritance, which can be a
> real pain sometimes. I become inclined to make them both modules and
> use separate meta-modules if need be, to keep things nicely symmetric.
> But really, why should I have to make such a fuss? Why do I have to
> draw so many abstract distinctions when there is no such thing in my
> actual model?

Why are you choosing to implement this in perhaps the worst OO way
possible? Why have you made metaclass inheritance important? Again:
consider composition.

> I think it would be a good idea to really give some deep consideration
> as to why modules and classes are distinct in Ruby. It's clear from
> Ruby's source that the distinction is self-inflicted to begin with.
> Why? Are we really gaining anything by the distinction, or are we just
> making things harder for ourselves w/o necessarily realizing it,
> simply because that's the "philosophy".
>
> Food for thought,

I'm sending it back. It's overcooked and watery.

-austin
--
Austin Ziegler * halostatue@gmail.com * http://www.halo...
* austin@halostatue.ca * http://www.halo...feed/
* austin@zieglers.ca

MenTaLguY

10/5/2007 10:16:00 PM

0

On Sat, 6 Oct 2007 06:06:45 +0900, Trans <transfire@gmail.com> wrote:
> I think it would be a good idea to really give some deep consideration
> as to why modules and classes are distinct in Ruby. Why?

One reason is to avoid ambiguity about object representations. Let's
say that instance methods of class A assume one representation, and the
instance methods of class B assume another, incompatible, representation
[1].

class C < A, B
end

Should A's methods or B's methods break when called on an instance of
C?

One solution I can think of immediately would be for a newly allocated
instance of C to allocate an instance of A and an instance of B behind
the scenes, delegating method calls to them as appropriate.

However, at that point it's starting to sound suspiciously like
aggregation... have you considered using aggregation rather than just
inheritance for modeling your problem?

-mental

[1] In Ruby 1.8, representations can be incompatible because they either
used instance variables with conflicting names, or because they are
of different RBasic types -- e.g. T_STRUCT versus T_DATA



Joel VanderWerf

10/5/2007 10:25:00 PM

0

MenTaLguY wrote:
> On Sat, 6 Oct 2007 06:06:45 +0900, Trans <transfire@gmail.com> wrote:
>> I think it would be a good idea to really give some deep consideration
>> as to why modules and classes are distinct in Ruby. Why?
>
> One reason is to avoid ambiguity about object representations. Let's
> say that instance methods of class A assume one representation, and the
> instance methods of class B assume another, incompatible, representation
> [1].
...
> [1] In Ruby 1.8, representations can be incompatible because they either
> used instance variables with conflicting names, or because they are
> of different RBasic types -- e.g. T_STRUCT versus T_DATA

Isn't ivar conflict an argument against mixins just as much as it is an
argument against MI?

Solutions to this have been discussed...

T_STRUCT vs T_DATA is still a problem for MI, of course. (As is T_DATA
vs T_DATA when the underlying C types are different.)

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

MenTaLguY

10/5/2007 10:47:00 PM

0

On Sat, 6 Oct 2007 07:25:13 +0900, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> Isn't ivar conflict an argument against mixins just as much as it is an
> argument against MI?

Yes, although I don't think it's as strong an argument as differing RBasic
types. Well-designed mixins can usually (not always) avoid using instance
variables, and the possibility of conflict can be greatly reduced, if you
give the instance variables meaningful suffixes.

That isn't to say that I've never experienced an ivar conflict, though...

-mental



Trans

10/5/2007 11:02:00 PM

0

Hi Austin,

It's been a while. Glad to see your still ready to go a round :)

On Oct 5, 3:13 pm, "Austin Ziegler" <halosta...@gmail.com> wrote:
> On 10/5/07, Trans <transf...@gmail.com> wrote:
>
> > So I working on little lib that's ripe for an adapter pattern, when I
> > see quite clearly that I have a bit of a dilemma. I have two clear
> > inheritance hierarchies converging. I want to create a
> > LinuxVideoPlayerApplication subclass, but it needs to inherit from
> > both VideoPlayerApplication and LinuxApplication.
>
> I think that you've got a problem here, and it won't be solved with MI.
> You need to reapproach the issue. I have yet to find a time when MI
> makes sense even in C++.

Huh. Seems to me whatever you call it, that's exactly how it is going
to end up. I've encapsulated two different behaviors and they are
going to end in one place --i.e. multiple inheritance. Whether I
implement it via classes, modules, composition or even code injection,
the formal result is the same. That's really the crux of my argument.

> > class VideoPlayerApplication < Application
> > class LinuxApplication < Application
>
> > Oh no!
>
> > class LinuxVideoPlayerApplication < VideoPlayerApplication
> > or
> > class LinuxVideoPlayerApplication < LinuxApplication
>
> Frankly, I don't think you've got a good design here, without seeing
> anything else.
>
> A LinuxApplication isn't sensible. What makes a LinuxApplication
> different from a GenericApplication or from a WindowsApplication? In
> other words, I think that you've set yourself up for the dichotomy by
> not considering this the right way.
>
> Think of it in terms of aspects. What are the aspects that make an
> application a Linux application? How can you pull those in cleanly?

Why do you think it is not sensible? I would say, a LinuxApplication
has a different null device method for instance, just to pick
something out the blue. Do you think it isn't sensible b/c a
LinuxApplication isn't something to be initialized --that it is just a
base class? But then the VideoPlayerApplication class isn't sensible
either for the same reason. Neither is useful until they come
together. Or is it not sensible b/c a LinuxApplication is something
more general than a VideoPlayerApplication? Well, that's a fair
argument for making the LinuxApplication the module of the two. But
still that's just a matter of degree not of completely different
character. Or is it not sensible for some other reason?

> > Ruby forces me make a choice. Which is "more real" I guess is it's
> > demand. But the choice is contrived. Both apply, and Ruby's strict
> > single-inheritance philosophy does nothing for me in the end except
> > make my life more complicated. One way or the other I am going to get
> > both behaviors in there. Period.
>
> That's fine, but nothing you've written suggests that MI is a good idea.
>
> > So as things are, I'm stuck with making one of them a module instead
> > of a class.
>
> Why?
>
> Avoid inheritance when you don't need it -- and you need it a lot less
> than you think. Composition is usually a better approach than
> inheritance.

What this point of having inheritance if we're just going to avoid it?
I can use composition in any language. Ruby's an OOP. Shouldn't we use
OOP and it's patterns where they apply? Isn't that the whole point?
Plus composition is generally slower. On an already slow language like
Ruby that kind of stinks.

> > But then I loose metaclass inheritance, which can be a
> > real pain sometimes. I become inclined to make them both modules and
> > use separate meta-modules if need be, to keep things nicely symmetric.
> > But really, why should I have to make such a fuss? Why do I have to
> > draw so many abstract distinctions when there is no such thing in my
> > actual model?
>
> Why are you choosing to implement this in perhaps the worst OO way
> possible? Why have you made metaclass inheritance important? Again:
> consider composition.

How is it the worse OO way possible? What you are advocating is not
OOP at all. Don't get me wrong. I have nothing against composition,
but I'm surprised you would suggest it in an OOP language to model
something that has a clear inheritance structure.

> > I think it would be a good idea to really give some deep consideration
> > as to why modules and classes are distinct in Ruby. It's clear from
> > Ruby's source that the distinction is self-inflicted to begin with.
> > Why? Are we really gaining anything by the distinction, or are we just
> > making things harder for ourselves w/o necessarily realizing it,
> > simply because that's the "philosophy".
>
> > Food for thought,
>
> I'm sending it back. It's overcooked and watery.

LOL.

That's because it's stew not potatoes ;)

T.


Rudi Cilibrasi

10/5/2007 11:22:00 PM

0

I agree with Austin. And here's a good explanation as to why:

http://brighton.ncsa.uiuc.edu/prajlich/T/n...

> I can use composition in any language. Ruby's an OOP. Shouldn't we use
> OOP and it's patterns where they apply? Isn't that the whole point?

In summary: inheritance is "white-box reuse" and composition is
"black-box reuse". There are strong arguments that essentially point
out that inheritance is a tighter coupling of parts and less
encapsulated in terms of abstraction than composition, which also
happens to be my favorite of the two.


Cheers,

-r.

On 10/5/07, Trans <transfire@gmail.com> wrote:
> Hi Austin,
>
> It's been a while. Glad to see your still ready to go a round :)
>
> On Oct 5, 3:13 pm, "Austin Ziegler" <halosta...@gmail.com> wrote:
> > On 10/5/07, Trans <transf...@gmail.com> wrote:
> >
> > > So I working on little lib that's ripe for an adapter pattern, when I
> > > see quite clearly that I have a bit of a dilemma. I have two clear
> > > inheritance hierarchies converging. I want to create a
> > > LinuxVideoPlayerApplication subclass, but it needs to inherit from
> > > both VideoPlayerApplication and LinuxApplication.
> >
> > I think that you've got a problem here, and it won't be solved with MI.
> > You need to reapproach the issue. I have yet to find a time when MI
> > makes sense even in C++.
>
> Huh. Seems to me whatever you call it, that's exactly how it is going
> to end up. I've encapsulated two different behaviors and they are
> going to end in one place --i.e. multiple inheritance. Whether I
> implement it via classes, modules, composition or even code injection,
> the formal result is the same. That's really the crux of my argument.
>
> > > class VideoPlayerApplication < Application
> > > class LinuxApplication < Application
> >
> > > Oh no!
> >
> > > class LinuxVideoPlayerApplication < VideoPlayerApplication
> > > or
> > > class LinuxVideoPlayerApplication < LinuxApplication
> >
> > Frankly, I don't think you've got a good design here, without seeing
> > anything else.
> >
> > A LinuxApplication isn't sensible. What makes a LinuxApplication
> > different from a GenericApplication or from a WindowsApplication? In
> > other words, I think that you've set yourself up for the dichotomy by
> > not considering this the right way.
> >
> > Think of it in terms of aspects. What are the aspects that make an
> > application a Linux application? How can you pull those in cleanly?
>
> Why do you think it is not sensible? I would say, a LinuxApplication
> has a different null device method for instance, just to pick
> something out the blue. Do you think it isn't sensible b/c a
> LinuxApplication isn't something to be initialized --that it is just a
> base class? But then the VideoPlayerApplication class isn't sensible
> either for the same reason. Neither is useful until they come
> together. Or is it not sensible b/c a LinuxApplication is something
> more general than a VideoPlayerApplication? Well, that's a fair
> argument for making the LinuxApplication the module of the two. But
> still that's just a matter of degree not of completely different
> character. Or is it not sensible for some other reason?
>
> > > Ruby forces me make a choice. Which is "more real" I guess is it's
> > > demand. But the choice is contrived. Both apply, and Ruby's strict
> > > single-inheritance philosophy does nothing for me in the end except
> > > make my life more complicated. One way or the other I am going to get
> > > both behaviors in there. Period.
> >
> > That's fine, but nothing you've written suggests that MI is a good idea.
> >
> > > So as things are, I'm stuck with making one of them a module instead
> > > of a class.
> >
> > Why?
> >
> > Avoid inheritance when you don't need it -- and you need it a lot less
> > than you think. Composition is usually a better approach than
> > inheritance.
>
> What this point of having inheritance if we're just going to avoid it?
> I can use composition in any language. Ruby's an OOP. Shouldn't we use
> OOP and it's patterns where they apply? Isn't that the whole point?
> Plus composition is generally slower. On an already slow language like
> Ruby that kind of stinks.
>
> > > But then I loose metaclass inheritance, which can be a
> > > real pain sometimes. I become inclined to make them both modules and
> > > use separate meta-modules if need be, to keep things nicely symmetric.
> > > But really, why should I have to make such a fuss? Why do I have to
> > > draw so many abstract distinctions when there is no such thing in my
> > > actual model?
> >
> > Why are you choosing to implement this in perhaps the worst OO way
> > possible? Why have you made metaclass inheritance important? Again:
> > consider composition.
>
> How is it the worse OO way possible? What you are advocating is not
> OOP at all. Don't get me wrong. I have nothing against composition,
> but I'm surprised you would suggest it in an OOP language to model
> something that has a clear inheritance structure.
>
> > > I think it would be a good idea to really give some deep consideration
> > > as to why modules and classes are distinct in Ruby. It's clear from
> > > Ruby's source that the distinction is self-inflicted to begin with.
> > > Why? Are we really gaining anything by the distinction, or are we just
> > > making things harder for ourselves w/o necessarily realizing it,
> > > simply because that's the "philosophy".
> >
> > > Food for thought,
> >
> > I'm sending it back. It's overcooked and watery.
>
> LOL.
>
> That's because it's stew not potatoes ;)
>
> T.
>
>
>


--
"We can try to do it by breaking free of the mental prison of
separation and exclusion and see the world in its interconnectedness
and non-separability, allowing new alternatives to emerge." -- after
Vandana Shiva

Eric Hodel

10/6/2007 12:18:00 AM

0

On Oct 5, 2007, at 16:02 , Trans wrote:

> What this point of having inheritance if we're just going to avoid it?
> I can use composition in any language. Ruby's an OOP. Shouldn't we use
> OOP and it's patterns where they apply? Isn't that the whole point?

No.

OO features are just another tool to use when you need it (note that
I said need, not want). Just because you can use an eight-pound
sledge for any nail-driving purpose doesn't mean you should.
Likewise you shouldn't use complicated OO features when simple
procedural code will suffice.

Keeping things simple benefits everyone, but yourself most
importantly. There's no reason to construct something so large you
can barely maintain or understand it.

WTF had an excellent post about this, including this quote from
Michael A. Jackson's Principles of Program Design:

> Programmers [...] often take refuge in an understandable, but
> disastrous, inclination towards complexity and ingenuity in their
> work. Forbidden to design anything larger than a program, they
> respond by making that program intricate enough to challenge their
> professional skill.

http://worsethanfailure.com/Comments/The-Mythical-Business-...

Instead of starting with objects, you should start with a method,
then add another. Objects will spring out of it naturally as you
refactor for reuse.

Attempting to determine your objects before writing any methods is
like performing surgery with meat-hooks and salad tongs. It can be
done, but most of the time you'll end up with a sloppy, sagging mess.

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars



Austin Ziegler

10/6/2007 12:21:00 AM

0

On 10/5/07, Trans <transfire@gmail.com> wrote:
> It's been a while. Glad to see your still ready to go a round :)

> On Oct 5, 3:13 pm, "Austin Ziegler" <halosta...@gmail.com> wrote:
>> On 10/5/07, Trans <transf...@gmail.com> wrote:
>>> So I working on little lib that's ripe for an adapter pattern, when
>>> I see quite clearly that I have a bit of a dilemma. I have two clear
>>> inheritance hierarchies converging. I want to create a
>>> LinuxVideoPlayerApplication subclass, but it needs to inherit from
>>> both VideoPlayerApplication and LinuxApplication.
>> I think that you've got a problem here, and it won't be solved with MI.
>> You need to reapproach the issue. I have yet to find a time when MI
>> makes sense even in C++.
> Huh. Seems to me whatever you call it, that's exactly how it is going
> to end up. I've encapsulated two different behaviors and they are
> going to end in one place --i.e. multiple inheritance. Whether I
> implement it via classes, modules, composition or even code injection,
> the formal result is the same. That's really the crux of my argument.

The problem with your argument is that it isn't actually based on
something correct. Composition isn't at all related to MI, although
delegation can fake it out pretty well, and with fewer problems (since
you're managing your delegation directly).

What you have is not a LinuxVideoPlayerAppllication but an Application
for Linux with VideoPlayer capabilities (this actually implies a lot
more than just what's written, but I'll leave it as that for now).

It's a bit harder to talk about the design because, as I said, it's
unclear what a LinuxApplication has that's separate from a generic
Application or why inheritance (of any sort) is the way to model that.

>>> So as things are, I'm stuck with making one of them a module instead
>>> of a class.
>> Why?
>>
>> Avoid inheritance when you don't need it -- and you need it a lot
>> less than you think. Composition is usually a better approach than
>> inheritance.
> What this point of having inheritance if we're just going to avoid it?
> I can use composition in any language. Ruby's an OOP. Shouldn't we use
> OOP and it's patterns where they apply? Isn't that the whole point?
> Plus composition is generally slower. On an already slow language like
> Ruby that kind of stinks.

There's nothing inherently slower about composition. You should use an
inheritance model when you can clearly say that something IS-A rather
than HAS-A. Let's consider:

A Video Player Application on Linux

Right? Well, it IS an Application. It HAS Linux support and HAS the
ability to play Video. One can break down Video support several ways,
too (and probably should). A video player has something that reads the
file (Reader), passes it through a (polymorphic with inheritance) Codec,
and then takes the Audio and Video streams and sends them to a
SoundPlayer and DisplayBuffer, that may or may not actually be visible
on screen.

Inheritance is important and powerful, but should only be used to
represent things that are essentially interchangeable. Otherwise,
composition is better.

>>> But then I loose metaclass inheritance, which can be a
>>> real pain sometimes. I become inclined to make them both modules and
>>> use separate meta-modules if need be, to keep things nicely symmetric.
>>> But really, why should I have to make such a fuss? Why do I have to
>>> draw so many abstract distinctions when there is no such thing in my
>>> actual model?
>> Why are you choosing to implement this in perhaps the worst OO way
>> possible? Why have you made metaclass inheritance important? Again:
>> consider composition.
> How is it the worse OO way possible? What you are advocating is not
> OOP at all. Don't get me wrong. I have nothing against composition,
> but I'm surprised you would suggest it in an OOP language to model
> something that has a clear inheritance structure.

But it doesn't have a clear inheritance structure. It's a contrived
inheritance structure. Do you consider JavaScript an OO language? You
should, because it is. It also doesn't have inheritance by default. (It
can be added, but it's not there by default.)

Like I said, I have yet to see where MI is better than composition and
delegation.

-austin
--
Austin Ziegler * halostatue@gmail.com * http://www.halo...
* austin@halostatue.ca * http://www.halo...feed/
* austin@zieglers.ca

Michael T. Richter

10/6/2007 12:37:00 AM

0

On Sat, 2007-06-10 at 07:13 +0900, Austin Ziegler wrote:

> Avoid inheritance when you don't need it -- and you need it a lot less
> than you think. Composition is usually a better approach than
> inheritance.


This is the big thing about OOP that I don't like: the "golden hammer"
solution of making everything a class and using inheritance as the
be-all, end-all of construction.

Inheritance makes things fragile, not robust. It interferes with
re-usability in most circumstances instead of enhancing it. Why is it
such a popular technique?!

--
Michael T. Richter <ttmrichter@gmail.com> (GoogleTalk:
ttmrichter@gmail.com)
There are two ways of constructing a software design. One way is to make
it so simple that there are obviously no deficiencies. And the other way
is to make it so complicated that there are no obvious deficiencies.
(Charles Hoare)

Michael T. Richter

10/6/2007 12:51:00 AM

0

On Sat, 2007-06-10 at 08:02 +0900, Trans wrote:

> > Avoid inheritance when you don't need it -- and you need it a lot less
> > than you think. Composition is usually a better approach than
> > inheritance.



> What this point of having inheritance if we're just going to avoid it?


"I use it because I have it" is not a valid reason for using any
language feature of any kind. Why do we have the plethora of
$-variables in Ruby if we're just going to avoid it? Why do we have the
loop method if we generally don't use it? Why do we have any language
constructs at all beyond 16 basic assembly language statements, in fact?

Switch over to cars for a moment. A car mechanic -- a good one, anyway
-- will have a huge chest of tools. Some of those tools only get used
perhaps once or twice a year. Why does he have them? Because when
they're used, they're the single best tool for the job and other tools
are just not adequate is why.

The features of a programming languages (as well as the set of
programming languages known) are the "mechanics tools" of the
professional programmer. If you're a decent programmer, you have quite
a few of them (much like a decent mechanic has quite a few tools in his
chest). But just like a decent mechanic doesn't randomly do brake
adjustments because he happens to have a set of brake calipers, you
shouldn't be stuffing everything into inheritance trees just because the
language you use supports inheritance.

Object-oriented programming has at its core objects. Inheritance is
just one tool used for manipulating objects. Composition is another.
Your question could easily be reworded (and it's a rewording I prefer
since this is the normal problem in libraries and applications) to:
"What is the point of supporting composition and aggregation if we're
just going to avoid them?"

Branch out. Investigate other ways of constructing programs. Look
specifically into decoupling of objects if you want a more flexible and
maintainable approach to building systems.


> I can use composition in any language. Ruby's an OOP. Shouldn't we use
> OOP and it's patterns where they apply? Isn't that the whole point?


Look into the Gang of Four's Design Patterns book sometime. Count the
patterns that use composition and aggregation over inheritance. And
read the part that warns against overuse of inheritance....

--
Michael T. Richter <ttmrichter@gmail.com> (GoogleTalk:
ttmrichter@gmail.com)
We should sell bloat credits, the way the government sells pollution
credits. Everybody's assigned a certain amount of bloat, and if they go
over, they have to purchase bloat credits from some other group that's
been more careful. (Bent Hagemark)