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