in reply to Re: Understanding 'Multiple Inheritance'
in thread Understanding 'Multiple Inheritance'

The heart of the big benefits from OO is encapsulation, not inheritance.

The heart of the big benefits from OO is polymorphism. Polymorphism encourages encapsulation, but absolutely requires inheritance.

Polymorphism allows you to derive (inherit) from a class and change its behaviour for certain methods. And that is the basic advantage of OO.

I can do encapsulation in non-OO programming. For example, I can create a private package-level cache of data, create random keys, and require that key to access the data for that "object" (abstract data type), rather than passing around a hash ref. I've created encapsulation.

What I can't do without OO is polymorphism. I cannot create a new ADT that has all of the functionality of the old ADT, except overriding some function to extend it. That requires inheritance.

As to MI - I don't avoid it. I embrace it as much as possible. The only thing is, that I've only found 1 time in about 10 years of OO programming where MI was the right answer. And that was 9 years ago. It's enough to convince me that languages without MI (such as Java) are seriously crippled for certain paradigms, although Java's MI (extends one class, implements many others) is sufficient for a lot of other paradigms.

Perl is somewhere between C++ and Java on MI. Many of perl's classes don't really have any useful constructor. Object types which don't need any construction, but can mix in code fragments (which is impossible in Java, but not C++) are often called "plugins" in Perl. This type of MI is incredibly useful in those problem spaces. And you may not have even realised you were using MI - many plugins "use base" on themselves for you (or equivalent). It's kind of an abuse on Exporter... but it works. And you can still choose to override these functions to extend them - giving you the polymorphism you need.

  • Comment on Re^2: Understanding 'Multiple Inheritance'

Replies are listed 'Best First'.
Re^3: Understanding 'Multiple Inheritance'
by chromatic (Archbishop) on Mar 07, 2005 at 19:40 UTC
    Polymorphism encourages encapsulation, but absolutely requires inheritance.

    Completely false.

    package RubberDuck; sub new { bless {}, shift } sub quack { print "Squeak!\n" } sub DESTROY { print "RubberDuck goes back in the toybox.\n" } package Mallard; sub new { bless {}, shift } sub quack { print "Quack!\n" } sub DESTROY { print "Mallard flies away.\n" } package main; for my $duck_class (qw( RubberDuck Mallard )) { my $duck = $duck_class->new(); $duck->quack(); }

    Duck typing, without inheritance.

    Polymorphism has ever so much more to do with method dispatch and type equivalence (in languages that care about such things and in situations where it matters) than it does about inheritance, which is merely an implementation detail of how to reuse code and to mark type equivalence in some cases.

      Polymorphism encourages encapsulation, but absolutely requires inheritance.
      Completely false.

      ? Not just "false" but "completely false"? So polymorphism neither encourages encapsulation nor requires inheritance?

      This is not polymorphism, this is overloaded functions, as in multimethods of perl 6. Your methods are, more or less:

      sub quack(RubberDuck $self) { ... } sub quack(Mallard $self) { ... }
      This is not polymorphism. Overloadable functions (same name, different contents) are usually found only in OO languages, but I don't think that this is causal. I think C may have overloadable functions in the not-too-distant future, if it doesn't already in the latest spec.

      package RubberDuck; sub new { bless {}, shift } sub make_noise { print "Plug yer ears!\n"; $_[0]->quack(); } sub quack { print "Squeak!\n" } sub DESTROY { print "RubberDuck goes back in the toybox.\n" } package Mallard; our @ISA = qw(RubberDuck); sub new { bless {}, shift } sub quack { print "Quack!\n" } sub DESTROY { print "Mallard flies away.\n" } package main; for my $duck_class (qw( RubberDuck Mallard )) { my $duck = $duck_class->new(); $duck->make_noise(); }

      This is polymorphism. The parent class calls a function in the parent class, but the derived class gets to intercept it and do stuff with it. That stuff may include calling the parent class, or, as in this example, it may not.

        So polymorphism neither encourages encapsulation nor requires inheritance?

        Yes, that's exactly right. You can have polymorphism without inheritance. You can have object orientation without inheritance. (Consider a prototype-based languages such as Self or JavaScript.) Almost no book or tutorial on object orientation explains that well, but that's a failure of imagination at best.

        This is not polymorphism, this is overloaded functions...

        My code declares two classes with identical interfaces and similar semantics. The classes have no relationship code-wise, neither sharing code nor inheriting from each other or from a common ancestor. Yet the main package treats objects of both classes identically, semantically and code-wise, and it works.

        How is that not polymorphism? Where is the overloading?

        This is polymorphism.

        Yes, your code also shows polymorphism -- specifically sub-type polymorphism. That's not the only type of polymorphism, however, and it's certainly not always the best type.

        You and chromatic are defining polymorphism differently, and then disagreeing about whether his example is polymorphism.

        But the thing is that his implicit definition is both more useful and more standard.

        Polymorphism is the ability for different data types to go through the same code and automatically be treated appropriately. One way to generate different data types that you might do this is to have a class and a subclass. (Or to have 2 subclasses.) But there is, in general, no need for them to be related in any way. It is just often convenient for them to be connected.

Re^3: Understanding 'Multiple Inheritance'
by Mugatu (Monk) on Mar 07, 2005 at 18:10 UTC
    The heart of the big benefits from OO is encapsulation, not inheritance.
    The heart of the big benefits from OO is polymorphism.

    As you two demonstrated, this is obviously up for debate. Any authoritative statement either way is bound to be disagreeable to one person or another. In this case, though, I think you're both right.

    A large part of good programming practice is finding the right abstractions for certain tasks. Polymorphism and encapsulation are both ways to abstract one thing or another, and I think objects are pretty good at doing both of those.

    Incidentally, I usually use object oriented techniques more for encapsulation, as Tilly suggests, than polymorphism, but I think they are two sides of the same coin. You can have one without the other, but they're not mutually exclusive.

Re^3: Understanding 'Multiple Inheritance'
by tilly (Archbishop) on Mar 08, 2005 at 02:19 UTC
    I disagree. More specifically while I agree that encapsulation is possible without OO, I believe that most of the advantages that most programmers saw when they moved to OO was that they began to use more encapsulation because it became simpler to do so.

    I also disagree that you can't do polymorphism without OO. There are plenty of ways to write code such that you'll get polymorphism. One obvious approach is to emulate how OO works by hand (this turns out to be fairly simple).

    About multiple inheritance, it sounds to me like you think that MI is a great idea, but it just keeps on not coming up as a good solution for you. However I'm going to guess that if you ran across a problem today that looked like what you used it for 9 years ago, you'd probably find that there was a perfectly good single inheritance solution available that you now have the programming maturity to find.

    Also note that I differentiate multiple inheritance from attempts to create mixins. For one thing mixins have the distinct advantage that you avoid the complications around how to decide which method to dispatch to when unrelated parents implement different versions. Since most of my complaints about MI have to do with exactly that problem, avoiding it does not seem to me to be a small change in semantics.

    That said, I generally don't like mixins in Perl, though I do in Ruby. The difference, as I've said many times, is how many uses I can amortize the effort of learning the interface over.