[% setvar title Objects : NEXT pseudoclass for method redispatch %]
Note: these documents may be out of date. Do not use as reference! |
To see what is currently happening visit http://www.perl6.org/
Objects : NEXT pseudoclass for method redispatch
Maintainer: Damian Conway <damian@conway.org> Date: 1 Sep 2000 Last Modified: 18 Sep 2000 Mailing List: perl6-language-objects@perl.org Number: 190 Version: 2 Status: Frozen
This RFC proposes a new pseudoclass named NEXT
.
This pseudoclass would provide a way of correctly redispatching a method
or an autoloaded method.
Perl 5 provides a pseudoclass named SUPER
that allows a method to
redispatch a call to the next available method in one of its parent
classes. This redispatch mechanism works by searching for an inherited
method in any of the ancestors of the current package (but not
necessarily the invocant's package). This works well in many cases, but
not when the next most appropriate method is actually in a sibling class
of the current package, rather than in an ancestor.
For example, consider invoking a debugging method named dump_info
on a derived class object:
$obj->dump_info();
In order to ensure that all the object's ancestral information
was also dumped, its dump_info
method might be structured like so:
package Derived; use base qw(Base1 Base2); sub dump_info { my ($self) = @_; $self->SUPER::dump_info(); print $self->{derived_info}; }
The various ancestral classes would then be structured similarly:
package Base1; use base qw(GrandBase1); sub dump_info { my ($self) = @_; $self->SUPER::dump_info(); print $self->{base1_info}; } package Base2; use base qw(GrandBase2 GrandBase3); sub dump_info { my ($self) = @_; $self->SUPER::dump_info(); print $self->{base2_info}; } # etc.
Unfortunately, this does not result in the derived object's complete
information being dumped, since each call to SUPER::dump_info
will only call a single (left-most) ancestral dump_info
. Thus only the
dump_info
methods in the left-most inheritance branch will ever
be called.
What is required here is a mechanism to resume the original dispatch process, rather than initiate a new one from the current point.
It is proposed that Perl 6 provide a new pseudoclass -- NEXT
--
to facilitate exactly that.
A method invocation in which the method name is explicitly qualified
with NEXT::
(e.g. $self-
NEXT::method(@args)>) would cause the
original dispatch that invoked the current method to be restarted and
the next suitable method called.
Another way of thinking of the effect of such a redispatch would be that
it repeats the original dispatch of $self-
method(@args)>, but ignores
all dispatch candidates until it has reached (and by-passed) the current
method. Of course, the mechanism wouldn't actually be implemented in
this inefficient manner.
Note that, after the redispatch, control returns to the original method.
AUTOLOAD
methodsThe NEXT
pseudoclass also solves the problem of how to allow
AUTOLOAD
methods to "decline" to handle particular invocations.
For example, with NEXT
it is possible to implement an AUTOLOAD
method that only handles method calls of the form get_...
and
set_...
and is effectively invisible to any other method requests
(which might then trigger other AUTOLOAD
s elsewhere in the
object's inheritance tree).
The implementation would look like this:
sub AUTOLOAD { $AUTOLOAD =~ s/.*:://; if ($AUTOLOAD =~ /^get_\w+$/) { # Handle getting... } elsif ($AUTOLOAD =~ /^set_\w+$/) { # Handle setting... } else { # Decline to handle, # passing the request on to someone else... shift->${\"NEXT::$AUTOLOAD"}(@_); } }
Note that the same trick could be applied by any method, to selectively refuse certain invocations, handing them on to some other inherited method instead. For example:
package IO::URL; use base 'IO::File'; sub open { my ($self, $filename, @args) = @_; if ($filename !~ /^(http|ftp):/) { $self->NEXT::open($filename, @args); } else { # Open URL... } }
None.
Presumably it would be necessary to cache the dispatch stack until the dispatched method finishes executing.
Alternatively, implementing the method dispatcher as a coroutine would make this very easy.
Conway, Object Oriented Perl, pp. 183-184.
RFC 8: The AUTOLOAD subroutine should be able to decline a request