auto_inherit, inherit

Ovid publiustemp-tapx at yahoo.com
Thu Oct 4 06:32:44 BST 2007


--- Eric Wilhelm <scratchcomputing at gmail.com> wrote:

> Well,
> 
>   package Foo;
>   use base 'TAP::Harness';
>   use constant auto_inherit => 1;
> 
>   package Bar;
>   use base 'TAP::Harness';
>   use constant auto_inherit => 1;
> 
> But the Foo->inherit("TAP::Harness") and Bar->inherit("Foo") has to 
> happen.  See App::Prove::require_harness().

Just to be clear: inheritance is an *awful* method of code reuse.  All
someone has to do is, say, write their own &_process method and scratch
their head wondering why things are broken.  Or maybe both Bar and Foo
authors are aware of the &_process method and they both override it. 
What do we do?

This magical double-inheritance takes all the problems of multiple
inheritance and provides it via subclassing.  It inverts the problem
and still maintains the problem.  That's a pretty neat trick :)

I was dubious about this idea in the beginning, but I really didn't pay
enough attention and I should have.  Inheriting from non-abstract base
classes is a dangerous thing and should not be done without a very
solid understanding of the consequences (which most developers won't
have in this case).

It *might* not bite us too much at first, but as more people add
*stuff*, we're going to get more complaints about this.  It's a design
flaw.

> This was really meant only to be a simple way to layer specialized 
> harnesses on top of each other.  As long as they all call
> SUPER::foo() for each overridden foo(), it's a valid mechanism.

The problem with this is that while you generally want SUPER:: for
constructors, oftimes you *don't* want to do that for overridden
methods (that's why we override, right?).  So when your subclass wants
to replace &foo, it often wants to do completely because the SUPER::
method is useless to it.  As long as the method signatures are
identical, that's quite valid.

> What about having two delegates doing the same
> thing?  
> How do they layer on top of each other?  Are they supposed to have 
> methods chained or in sequence?

Delegation is a better choice, as you don't accidentally override
private/protected methods, but we still have the chained/sequence
problem with your inheritance scheme.  I'm not sure how to fix this,
but inheritance is the wrong approach.  Schwern mentioned traits
earlier and Andy A nixed that pretty quickly, but I really can't think
of any other way -- I mean, this is the problem traits were meant to
solve.

> In other words, do you want to say that subclassing TAP::Harness is 
> simply not the way to customize/specialize it?  Fine, but I think 
> getting that API right will be difficult, it would have to be easy to
> understand or it raises the barrier to entry, and it seems like it 
> would be awfully susceptible to an "ivory tower" issue.  I also think

> it might be limiting the flexibility.  If that's done only in the 
> service of some presumed "safety", I would call that a net loss.

Presumed "safety"?  How about calling that "presumed non-buggy code"? 
I think you have an idea of the core problem here and you're trying to
dismiss it before anyone says anything.  Subclassing is an *awful*
method of code reuse.  Many, many people have been bitten by this.  I
agree with you completely about the need to find an easy to understand
alternative, but subclassing is wrong (that being said, if we can't
figure out anything else, I won't stand in its way).

Cheers,
Ovid

--
Buy the book  - http://www.oreilly.com/catalog/perlhks/
Perl and CGI  - http://users.easystreet.com/ovid/cgi_course/
Personal blog - http://publius-ovidius.livejournal.com/
Tech blog     - http://use.perl.org/~Ovid/journal/


More information about the tapx-dev mailing list