This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Objects : NEXT pseudoclass for method redispatch =head1 VERSION Maintainer: Damian Conway <[EMAIL PROTECTED]> Date: 1 Sep 2000 Last Modified: 18 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 190 Version: 2 Status: Frozen =head1 ABSTRACT This RFC proposes a new pseudoclass named C<NEXT>. This pseudoclass would provide a way of correctly redispatching a method or an autoloaded method. =head1 DESCRIPTION Perl 5 provides a pseudoclass named C<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 I<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 C<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 C<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 C<SUPER::dump_info> will only call a single (left-most) ancestral C<dump_info>. Thus only the C<dump_info> methods in the left-most inheritance branch will ever be called. What is required here is a mechanism to resume the I<original> dispatch process, rather than initiate a new one from the current point. It is proposed that Perl 6 provide a new pseudoclass -- C<NEXT> -- to facilitate exactly that. A method invocation in which the method name is explicitly qualified with C<NEXT::> (e.g. C<$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 C<$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. =head2 Redispatch of C<AUTOLOAD> methods The C<NEXT> pseudoclass also solves the problem of how to allow C<AUTOLOAD> methods to "decline" to handle particular invocations. For example, with C<NEXT> it is possible to implement an C<AUTOLOAD> method that only handles method calls of the form C<get_...> and C<set_...> and is effectively invisible to any other method requests (which might then trigger other C<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... } } =head1 MIGRATION ISSUES None. =head1 IMPLEMENTATION 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. =head1 REFERENCES Conway, I<Object Oriented Perl>, pp. 183-184. RFC 8: The AUTOLOAD subroutine should be able to decline a request