Reference overloading helps inheritance

A

Anno Siegel

Inheritance in Perl OO has its difficulties when it comes to data
encapsulation. Basically, it can't be done without a peek at the
implementation of the superclass.

A frequent situation is that the inheriting class contains an object
of the superclass (or, more generally, has a method that returns a
superclass object), and you want it to respond to the methods of the
superclass. But let me use a concrete example, the generalization
will be obvious.

Consider a class "Tape", whose objects are conceptually snapshots of
some files or directories at a given time (not necessarily on magnetic
tape, but that's a nice short name). The implementation is a basic
hash-as-a-record:

bless {
name => $name,
...
time => Time::piece( ...),
}, Tape;

sub name { $_[ 0]->{ name} }
sub time { $_[ 0]->{ time} }

Now I want Tape to respond to the methods of Time::piece, that is, I
want to put "Time::piece" on @Tape::ISA. (Because of the overloading
Time::piece does, this means I can compare tapes with each other, or
with other dates (Time::piece objects) to see which is older. Handy
when deciding which tape to overwrite.)

One way of doing this is through Tape::AUTOLOAD. That can be considered
standard, I won't go into the possible variants here.

Instead of AUTOLOAD one can also use overload, which was new to me.
A peek at the implementation of Time::piece shows that the objects
are array-refs. So, if we can make Time::piece think that Tape objects
are the right kind of array ref, we're done. But that is what overloading
"@{}" does. So, in package Tape, saying

use base qw( Time::piece);
use overload ( '@{}' => 'time' );

is all that's needed to make Tape objects inherit from Time::piece.
That's pretty minimal.

The method isn't entirely clean, but some methods that are described
in Perl's OO recommendations are less so. It relies on the fact that
the superclass uses a particular (overloadable) data type for its
implementation, but on none of the further details. Obviously, it also
occupies that particular reference overloading, so if you need that
for something else, you're out of luck.

The implementation also assumes that the inherited data type is different
from the data type of the inheriting class. Otherwise, overloading
your own data type is still do-able, but a little involved. This
restriction can be worked around by yielding and making your data type
something else (wrap a scalar ref around it, for instance), but that
makes the method less attractive.

I'm surely not the first to make the observation that overloading can
help inheritance in this way, but since I didn't know about it, I
conclude that it isn't "well known" and deserves a mention :)

Anno
 
U

Uri Guttman

AS> Inheritance in Perl OO has its difficulties when it comes to data
AS> encapsulation. Basically, it can't be done without a peek at the
AS> implementation of the superclass.

some modules will do this for you. see the class:: modules by damian conway.

AS> A frequent situation is that the inheriting class contains an object
AS> of the superclass (or, more generally, has a method that returns a
AS> superclass object), and you want it to respond to the methods of the
AS> superclass. But let me use a concrete example, the generalization
AS> will be obvious.


AS> Now I want Tape to respond to the methods of Time::piece, that is, I
AS> want to put "Time::piece" on @Tape::ISA. (Because of the overloading
AS> Time::piece does, this means I can compare tapes with each other, or
AS> with other dates (Time::piece objects) to see which is older. Handy
AS> when deciding which tape to overwrite.)

this is done by damian's class::delegate module. it can make methods in
the owner (the object that has the other object) that call through to
the owned object.

uri
 
A

Anno Siegel

Uri Guttman said:
AS> Inheritance in Perl OO has its difficulties when it comes to data
AS> encapsulation. Basically, it can't be done without a peek at the
AS> implementation of the superclass.

some modules will do this for you. see the class:: modules by damian conway.

AS> A frequent situation is that the inheriting class contains an object
AS> of the superclass (or, more generally, has a method that returns a
AS> superclass object), and you want it to respond to the methods of the
AS> superclass. But let me use a concrete example, the generalization
AS> will be obvious.

AS> Now I want Tape to respond to the methods of Time::piece, that is, I
AS> want to put "Time::piece" on @Tape::ISA. (Because of the overloading
AS> Time::piece does, this means I can compare tapes with each other, or
AS> with other dates (Time::piece objects) to see which is older. Handy
AS> when deciding which tape to overwrite.)

this is done by damian's class::delegate module. it can make methods in
the owner (the object that has the other object) that call through to
the owned object.

Yes, it does, and it does a lot more than "my" method, and also some less
(it only works with hash objects). It uses the time-honored AUTOLOAD
to do run-time delegation, with its own method-caching and more. BTW,
the author seems to be Kurt Starsinic, not Damian.

However, the point of my posting was to show how to make Perl's native
inheritance (through @ISA) work if your object happens to contain (or
otherwise create) a superclass object. The point is that you can turn
an existing HAS-A relation into a working inheritance relation in two
statements (if applicable). It is a method that an OO programmer in
Perl should know about. That some modules do a more profound job (like
establishing the HAS-A relation in the first place), is irrelevant.

Anno
 
A

Anno Siegel

Uri Guttman said:
AS> Inheritance in Perl OO has its difficulties when it comes to data
AS> encapsulation. Basically, it can't be done without a peek at the
AS> implementation of the superclass.

some modules will do this for you. see the class:: modules by damian conway.

AS> A frequent situation is that the inheriting class contains an object
AS> of the superclass (or, more generally, has a method that returns a
AS> superclass object), and you want it to respond to the methods of the
AS> superclass. But let me use a concrete example, the generalization
AS> will be obvious.

AS> Now I want Tape to respond to the methods of Time::piece, that is, I
AS> want to put "Time::piece" on @Tape::ISA. (Because of the overloading
AS> Time::piece does, this means I can compare tapes with each other, or
AS> with other dates (Time::piece objects) to see which is older. Handy
AS> when deciding which tape to overwrite.)

this is done by damian's class::delegate module. it can make methods in
the owner (the object that has the other object) that call through to
the owned object.

Yes, it does, and it does a lot more than "my" method, and also some less
(it only works with hash objects). It uses the time-honored AUTOLOAD
to do run-time delegation, with its own method-caching and more. BTW,
the author seems to be Kurt Starsinic, not Damian.

However, the point of my posting was to show how to make Perl's native
inheritance (through @ISA) work if your object happens to contain (or
otherwise create) a superclass object. The point is that you can turn
an existing HAS-A relation into a working inheritance relation in two
statements (if applicable). It is a method that an OO programmer in
Perl should know about. That some modules do a more profound job (like
establishing the HAS-A relation in the first place), is irrelevant.

Anno
 
U

Uri Guttman

AS> Yes, it does, and it does a lot more than "my" method, and also some less
AS> (it only works with hash objects). It uses the time-honored AUTOLOAD
AS> to do run-time delegation, with its own method-caching and more. BTW,
AS> the author seems to be Kurt Starsinic, not Damian.

i am farily sure damian wrote it originally and gave it to kurt to
maintain. he has done that with a bunch of his modules. he doesn't have
the time to maintain all of them once he has created them.

AS> However, the point of my posting was to show how to make Perl's
AS> native inheritance (through @ISA) work if your object happens to
AS> contain (or otherwise create) a superclass object. The point is
AS> that you can turn an existing HAS-A relation into a working
AS> inheritance relation in two statements (if applicable). It is a
AS> method that an OO programmer in Perl should know about. That some
AS> modules do a more profound job (like establishing the HAS-A
AS> relation in the first place), is irrelevant.

i like HAS-A more than ISA and use it a fair amount but i don't always
do direct delegation. i will take another peek at your stuff and see if
it is worth stealing. one side issue it that overloading is slower AFAIK
(like tying is very slow we know).

uri
 
A

Anno Siegel

AS> However, the point of my posting was to show how to make Perl's
AS> native inheritance (through @ISA) work if your object happens to
AS> contain (or otherwise create) a superclass object. The point is
AS> that you can turn an existing HAS-A relation into a working
AS> inheritance relation in two statements (if applicable). It is a
AS> method that an OO programmer in Perl should know about. That some
AS> modules do a more profound job (like establishing the HAS-A
AS> relation in the first place), is irrelevant.

i like HAS-A more than ISA and use it a fair amount but i don't always
do direct delegation. i will take another peek at your stuff and see if
it is worth stealing. one side issue it that overloading is slower AFAIK
(like tying is very slow we know).

Overloading is slightly slower than a plain method call (about a third is
what I benchmarked, though these small differences are hard to measure).
That's no way near the loss you deal with in a typical tie.

Anno
 
A

Anno Siegel

AS> However, the point of my posting was to show how to make Perl's
AS> native inheritance (through @ISA) work if your object happens to
AS> contain (or otherwise create) a superclass object. The point is
AS> that you can turn an existing HAS-A relation into a working
AS> inheritance relation in two statements (if applicable). It is a
AS> method that an OO programmer in Perl should know about. That some
AS> modules do a more profound job (like establishing the HAS-A
AS> relation in the first place), is irrelevant.

i like HAS-A more than ISA and use it a fair amount but i don't always
do direct delegation. i will take another peek at your stuff and see if
it is worth stealing. one side issue it that overloading is slower AFAIK
(like tying is very slow we know).

Overloading is slightly slower than a plain method call (about a third is
what I benchmarked, though these small differences are hard to measure).
That's nowhere near the loss you deal with in a typical tie.

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top