NAME
NEXT.pm - Provide a pseudo-class NEXT that allows method redispatch
SYNOPSIS
use NEXT;
package A;
sub A::method { print "$_[0]: A method\n"; $_[0]->NEXT::method() }
sub A::DESTROY { print "$_[0]: A dtor\n"; $_[0]->NEXT::DESTROY() }
package B;
use base qw( A );
sub B::AUTOLOAD { print "$_[0]: B AUTOLOAD\n"; $_[0]->NEXT::AUTOLOAD() }
sub B::DESTROY { print "$_[0]: B dtor\n"; $_[0]->NEXT::DESTROY() }
package C;
sub C::method { print "$_[0]: C method\n"; $_[0]->NEXT::method() }
sub C::AUTOLOAD { print "$_[0]: C AUTOLOAD\n"; $_[0]->NEXT::AUTOLOAD() }
sub C::DESTROY { print "$_[0]: C dtor\n"; $_[0]->NEXT::DESTROY() }
package D;
use base qw( B C );
sub D::method { print "$_[0]: D method\n"; $_[0]->NEXT::method() }
sub D::AUTOLOAD { print "$_[0]: D AUTOLOAD\n"; $_[0]->NEXT::AUTOLOAD() }
sub D::DESTROY { print "$_[0]: D dtor\n"; $_[0]->NEXT::DESTROY() }
package main;
my $obj = bless {}, "D";
$obj->method(); # Calls D::method, A::method, C::method
$obj->missing_method(); # Calls D::AUTOLOAD, B::AUTOLOAD, C::AUTOLOAD
# Clean-up calls D::DESTROY, B::DESTROY, A::DESTROY, C::DESTROY
DESCRIPTION
NEXT.pm adds a pseudoclass named NEXT
to any program that uses it. If a method m
calls $self-
NEXT::m()>, the call to m
is redispatched as if the calling method had not originally been found.
In other words, a call to $self-
NEXT::m()> resumes the depth-first, left-to-right search of $self
's class hierarchy that resulted in the original call to m
.
Note that this is not the same thing as $self-
SUPER::m()>, which begins a new dispatch that is restricted to searching the ancestors of the current class. $self-
NEXT::m()> can backtrack past the current class -- to look for a suitable method in other ancestors of $self
-- whereas $self-
SUPER::m()> cannot.
A typical use would be in the destructors of a class hierarchy, as illustrated in the synopsis above. Each class in the hierarchy has a DESTROY method that performs some class-specific action and then redispatches the call up the hierarchy. As a result, when an object of class D is destroyed, the destructors of all its parent classes are called (in depth-first, left-to-right order).
Another typical use of redispatch would be in AUTOLOAD
'ed methods. If such a method determined that it was not able to handle a particular call, it might choose to redispatch that call, in the hope that some other AUTOLOAD
(above it, or to its left) might do better.
Note that it is a fatal error for any method (including AUTOLOAD
) to attempt to redispatch any method except itself. For example:
sub D::oops { print "oops!\n"; $_[0]->NEXT::other_method() }
AUTHOR
Damian Conway (damian@conway.org)
BUGS AND IRRITATIONS
Because it's a module, not an integral part of the interpreter, NEXT.pm has to guess where the surrounding call was found in the method look-up sequence. In the presence of diamond inheritance patterns it occasionally guesses wrong.
It's also too slow (despite caching).
Comment, suggestions, and patches welcome.
COPYRIGHT
Copyright (c) 2000-2001, Damian Conway. All Rights Reserved.
This module is free software. It may be used, redistributed
and/or modified under the same terms as Perl itself.