> I can most certainly think of cases where a base class's DESTROY does
> something a derived class doesn't like.  Consider your example,
> File::Lock.  File::Lock::DESTROY calls flock($fh, LOCK_UN).  I derive
> File::Lock::Mac from File::Lock.  Uh oh, Macs don't implement flock!
> Under your proposal, I'm screwed.

One approach, something that we can steal from Java, is that of implicit
versus explicit constructor/destructor chaining. If a function is written
as in Damian's proposal, then it would automatically have the parent
SETUP/DESTROY called for it. In certain cases, like the one in which you
proposed, you'd want to explicitly bypass the parent DESTROY.

sub DESTROY {
  my $self = shift;
  $self->UNIVERSAL::DESTROY(@_);
}

would skip the automatic chaining because the function contains an
explicit call to a superclass's DESTROY. In this case, Assuming File::Lock
'isa UNIVERSAL' as some default base class, then we're telling Perl to
skip UNIVERSAL in the chain as it goes up. In cases of more complex class
hierarchies, you can explicitly call one parent class's DESTROY, and skip
anothers. It allows control ONLY if you want it....if you don't do any
constructor/destructor chaining, then it would handle it for you.

Two things: First, perl would probably need to search the entire optree of
the function to see if it does call a superclass. Problems can happen with
eval calling a super-constructor that an op-tree parser couldn't find. I
suppose one could call it a feature that an eval'ed superclass-contructor
call causes that constructor to be called AS WELL AS the default chaining
system.

Another approach is to detect at the end of the function if the function
was called during it's lifetime, and call SUPER::SETUP at the end if it
was not, but this is a bad idea because the parent's constructor should be
called BEFORE the child's, so the child has the ability to augment and
override it's parent's settings.

And finally, a problem with this approach is that if you do call the
super-contructor yourself, you now have to start the chains in the parents
all by yourself as well. If you have four superclasses, and want to bypass
one of them, you need to manually call the other three. Adding another
'break's it. I suppose you could do nifty iteration through the ISA array
and skipping the bad one, however. I'm just trying to point out the
flaws in what I've proposed. :)


And finally, I don't believe you should force every module author to do
explicit superclass-calls themselves, as many people will forget to do it,
creating hidden bugs that can only be found when incriminating someone
else...hiding the true cause of why it won't be working.

Mike Lambert

Reply via email to