in reply to Understanding 'Multiple Inheritance'

I love Perl, but it's "object orientation" is incredibly brittle as a result of it being so damned ad-hoc. Really, Perl is name space oriented, and the actual storage of member data is up to the creator of a class. Typically this is done by blessing a hash into a class, and then making the "member variables" be elements of said hash. This, apart from being inefficient, is functional in the case of stand alone classes. It becomes dangerous when you inherit from another class as name clashes can occur, and the dangerousness increases geometrically with the size of your inheritence family.

In either C++ or Java, member variables are explicitly specified as being either public, protected, or private. If they are private, then derived classes cannot even see them, and if they are protected, then descendants can see them, but there is name-spacing such that in the case of a base and derived class having a duplicate name, there are actually two distinct variables. In this case, I believe access to a variable in a derived class defaults to the one in the child class, and (in the case of protected and public) the parent class's variable can be accessed by explicitly naming it with the parent class's name. The base class will know nothing of the child class's variable by the same name.

Unfortunately, in Perl you're just stuck with everything being in a single hash. The best thing I can think to do is to have your hash be two-tiered, with the first level of keys being class names, and the second level being member data for the corresponding class. This saves you from having classes in a hierarchy carelessly step on one another's data. So, instead of seeing methods like this...

sub set_foo { my ($self, $val) = @_; $self->{foo} = $val; }
you would instead have stuff like...
sub set_foo { my ($self, $val) = @_; $self->{ref($self)}{foo} = $val; }

Of course, this has two problems... First of all, everyone has to agree to do it. If you have ultimate control over all classes in the hierarchy, then maybe this isn't a problem, but what if you want to write classes derived from a class provided by a third party library? You are at their mercy. Also, another problem is that unlike C++ and Java which effect this name-spacing at compile time, this solution in Perl does it at run time, and we end up paying a penalty for having to drill through not one level of a hash, but two. It's bad enough as it is that we have to deal with hashes pretending to be objects. Slowing down member variable access by a factor of two might be unacceptable.

As best I can tell, Python also drops the ball on inheritance. The local dictionary associated with every Python object is basically the same thing as what we have in Perl, albeit built into the language core explicitly.

Does anyone know if Perl6 is going to suck less in this regard? I would truly love to have proper objects in Perl. The present ones are disappointing.

Replies are listed 'Best First'.
Re: Inheritance can be messy in Perl. Multiple inheritance can be disastrous.
by jdporter (Paladin) on Mar 07, 2005 at 17:10 UTC

    Pattern I see repeated over and over is that people who complain about Perl's OO got their notions of what's good OO from programming in other languages. Perl's OO in and of itself is powerful and useful; it's just a matter of grokking the fu (so to speak).

    Of course, necessity (perceived or otherwise) being what it is, there are numerous modules out there which seek to give a more rigorous form of OO to Perl - mostly in the Class space. I generally try to make perl's intrinsic OO bits work for me, whenever possible.

    Most of the time, I have full control of the class hierarchy, which, as you said, obviates the problem of member name conflicts. Even so, it's possible for things to get hairy; so to head that off, I take the Java approach to multiple inheritance, and stipulate that only one line of inheritance can define member data.

    Occasionally, I do use other people's classes which are designed to be subclassed; in such cases, if I need to add member data, I'll go to some extreme in the naming:

    package Squatch::Substandard; use Squatch::Standard; use base qw(Squatch::Standard); sub dingies { return $_[0]{'Squatch::Substandard::dingies'} }
    Unfortunately, in Perl you're just stuck with everything being in a single hash.
    It's true that you only get one scalar (a reference) to bless into objecthood; but it doesn't have to be a hash. And in any case, there's other ways of dealing with this "limitation" than:
    to have your hash be two-tiered, with the first level of keys being class names, and the second level being member data for the corresponding class.
    And anyway, once you've done that, you're 69% of the way to having extension by aggregation, which (arguably) is a better way to do type extension anyway.
    another problem is that unlike C++ and Java which effect this name-spacing at compile time, this solution in Perl does it at run time
    That could be said about everything else in perl. If you've drunk the Perl kool-aid, you don't bat an eye at issues like this.
    Does anyone know if Perl6 is going to suck less in this regard?
    Why don't you read the Perl6 docs and decide for yourself? Your definition of "suck" may be substantially different than a lot of perl users'.
      It's true that you only get one scalar (a reference) to bless into objecthood; but it doesn't have to be a hash.
      Indeed, but don't even think for a microsecond that that's a feature. It's not. Try subclassing from the class that uses references to arrays as objects - with a variable amount of data members. Try subclassing from a class that's using blessed closures as objects, and having the need to store instance data as well. Try subclassing from scalar references. Try doing MI from two classes that both use array references as objects - even if you have no instance data to store yourself.

      If you want to play friendly with potential subclassers, you either use references to hashes, or a technique that uses only the reference, and not what's it pointing to, like some fly weight pattern variations, or inside out objects, or Lexical::Attributes.

        If you're trying to do Java programming in Perl, you deserve the pain you get. ;-)
Re: Inheritance can be messy in Perl. Multiple inheritance can be disastrous.
by Anonymous Monk on Mar 08, 2005 at 09:32 UTC
    As best I can tell, Python also drops the ball on inheritance. The local dictionary associated with every Python object is basically the same thing as what we have in Perl, albeit built into the language core explicitly.
    That's not a coincidence. Larry looked a lot at Python when designing Perl's OO system.

    As for the rest of your articly, I fully agree.