On Tue, Dec 14, 2004 at 03:28:27PM +0200, Yuval Kogman wrote:
> I'm sufferring from MI headaches, which would all go away if search
> into ISA could be breadth first.

Does NEXT.pm help?
http://search.cpan.org/dist/NEXT/

If not directly, maybe you can make use of its techniques.


> I have
> 
>       FishStick
>               Food
>                       Whatever
>               Fish
>                       Animal
> 
> and the normal super path for FishStick is
> 
>       Food Whatever Fish Animal
> 
> I'd like to be able to say
> 
>       package FishStick;
>       use inheritance 'breadth_first';
> 
> and have perl dispatch calls on FishStick thingys with a super path
> like this:
> 
>       Food Fish Whatever Animal
> 
> If Whatever defines a ->choke method, and so does Fish, I would like
> 
>       $fishstick->choke;
> 
> to use Fish::choke, and not Whatever::choke. Not that a dead fish
> choking makes any sense.

Ugg, diamond inheritence.  It would be easier to break it up using delegation
than try to hack around the damage.

Fishstick isa  Food
Fishstick hasa Fish

Fish isa Animal

Food hasa Animal
Food hasa Whatever

This is a more accurate model, when you think about it.  A fish stick does
not act like a fish.  It acts like food.  It contains fish (so they say).

Food does not act like an animal, but it may contain any number of animals
and these days a whole lot of whatever.

A fish is, in fact, an animal.

If you wish to maintain the illusion of inheritance you can override
isa() and can() such that...

        package Fishstick;
        @ISA = qw(Food);
        @HASA = qw(Fish Whatever);

        # and similar for can()
        sub isa {
                my($class, $isa) = @_;

                return 1 if $class->SUPER::isa($isa);
                foreach my $hasa (@HASA) {
                        return 1 if $hasa->isa($isa);
                }

                return 0;
        }

And a simple AUTOLOAD can do the dispatch, if you still want it.  I'd
recommend against it because, as mentioned above, the behaviors of your
hasa relationships (ie. Fish) don't necessarily make sense for the container
(ie. FishStick).  So its better to choose one by one.

        sub AUTOLOAD {
                my($meth) = $AUTOLOAD =~ /([^:]+)$/;

                foreach my $hasa (@HASA) {
                        my $ref = $hasa->can($meth);
                        $_[0] = $self->{things}{$hasa};
                        goto &$ref if $ref;
                }

                die "can't find that method";
        }

And you can get clever about caching so the AUTOLOAD only gets called once
for each method, etc.


-- 
Michael G Schwern        [EMAIL PROTECTED]  http://www.pobox.com/~schwern/
Quando Omni Flunkus Moritati
        -- Red Green

Reply via email to