perlcheat is a reference, not tutorial.
[p5sagit/p5-mst-13.2.git] / lib / NEXT.pm
CommitLineData
e4783b1c 1package NEXT;
52138ef3 2$VERSION = '0.52';
e4783b1c 3use Carp;
4use strict;
5
52138ef3 6sub NEXT::ELSEWHERE::ancestors
e4783b1c 7{
13021a80 8 my @inlist = shift;
e4783b1c 9 my @outlist = ();
13021a80 10 while (my $next = shift @inlist) {
11 push @outlist, $next;
e4783b1c 12 no strict 'refs';
13 unshift @inlist, @{"$outlist[-1]::ISA"};
14 }
15 return @outlist;
16}
17
18sub AUTOLOAD
19{
20 my ($self) = @_;
21 my $caller = (caller(1))[3];
22 my $wanted = $NEXT::AUTOLOAD || 'NEXT::AUTOLOAD';
23 undef $NEXT::AUTOLOAD;
24 my ($caller_class, $caller_method) = $caller =~ m{(.*)::(.*)}g;
25 my ($wanted_class, $wanted_method) = $wanted =~ m{(.*)::(.*)}g;
26 croak "Can't call $wanted from $caller"
27 unless $caller_method eq $wanted_method;
28
13021a80 29 local ($NEXT::NEXT{$self,$wanted_method}, $NEXT::SEEN) =
30 ($NEXT::NEXT{$self,$wanted_method}, $NEXT::SEEN);
e4783b1c 31
13021a80 32
33 unless ($NEXT::NEXT{$self,$wanted_method}) {
34 my @forebears =
52138ef3 35 NEXT::ELSEWHERE::ancestors ref $self || $self,
36 $wanted_class;
e4783b1c 37 while (@forebears) {
38 last if shift @forebears eq $caller_class
39 }
40 no strict 'refs';
41 @{$NEXT::NEXT{$self,$wanted_method}} =
55a1c97c 42 map { *{"${_}::$caller_method"}{CODE}||() } @forebears
43 unless $wanted_method eq 'AUTOLOAD';
e4783b1c 44 @{$NEXT::NEXT{$self,$wanted_method}} =
13021a80 45 map { (*{"${_}::AUTOLOAD"}{CODE}) ? "${_}::AUTOLOAD" : ()} @forebears
55a1c97c 46 unless @{$NEXT::NEXT{$self,$wanted_method}||[]};
52138ef3 47 $NEXT::SEEN->{$self,*{$caller}{CODE}}++;
55a1c97c 48 }
49 my $call_method = shift @{$NEXT::NEXT{$self,$wanted_method}};
52138ef3 50 while ($wanted_class =~ /^NEXT:.*:(UNSEEN|DISTINCT):/ && defined $call_method
13021a80 51 && $NEXT::SEEN->{$self,$call_method}++) {
52 $call_method = shift @{$NEXT::NEXT{$self,$wanted_method}};
e4783b1c 53 }
13021a80 54 unless (defined $call_method) {
55 return unless $wanted_class =~ /^NEXT:.*:ACTUAL/;
56 (local $Carp::CarpLevel)++;
57 croak qq(Can't locate object method "$wanted_method" ),
58 qq(via package "$caller_class");
59 };
52138ef3 60 return $self->$call_method(@_[1..$#_]) if ref $call_method eq 'CODE';
13021a80 61 no strict 'refs';
62 ($wanted_method=${$caller_class."::AUTOLOAD"}) =~ s/.*:://
63 if $wanted_method eq 'AUTOLOAD';
64 $$call_method = $caller_class."::NEXT::".$wanted_method;
65 return $call_method->(@_);
e4783b1c 66}
67
13021a80 68no strict 'vars';
69package NEXT::UNSEEN; @ISA = 'NEXT';
52138ef3 70package NEXT::DISTINCT; @ISA = 'NEXT';
13021a80 71package NEXT::ACTUAL; @ISA = 'NEXT';
72package NEXT::ACTUAL::UNSEEN; @ISA = 'NEXT';
52138ef3 73package NEXT::ACTUAL::DISTINCT; @ISA = 'NEXT';
13021a80 74package NEXT::UNSEEN::ACTUAL; @ISA = 'NEXT';
52138ef3 75package NEXT::DISTINCT::ACTUAL; @ISA = 'NEXT';
76package EVERY; @ISA = 'NEXT';
13021a80 77
e4783b1c 781;
79
80__END__
81
82=head1 NAME
83
84NEXT.pm - Provide a pseudo-class NEXT that allows method redispatch
85
86
87=head1 SYNOPSIS
88
13021a80 89 use NEXT;
e4783b1c 90
13021a80 91 package A;
92 sub A::method { print "$_[0]: A method\n"; $_[0]->NEXT::method() }
93 sub A::DESTROY { print "$_[0]: A dtor\n"; $_[0]->NEXT::DESTROY() }
e4783b1c 94
13021a80 95 package B;
96 use base qw( A );
97 sub B::AUTOLOAD { print "$_[0]: B AUTOLOAD\n"; $_[0]->NEXT::AUTOLOAD() }
98 sub B::DESTROY { print "$_[0]: B dtor\n"; $_[0]->NEXT::DESTROY() }
e4783b1c 99
13021a80 100 package C;
101 sub C::method { print "$_[0]: C method\n"; $_[0]->NEXT::method() }
102 sub C::AUTOLOAD { print "$_[0]: C AUTOLOAD\n"; $_[0]->NEXT::AUTOLOAD() }
103 sub C::DESTROY { print "$_[0]: C dtor\n"; $_[0]->NEXT::DESTROY() }
e4783b1c 104
13021a80 105 package D;
106 use base qw( B C );
107 sub D::method { print "$_[0]: D method\n"; $_[0]->NEXT::method() }
108 sub D::AUTOLOAD { print "$_[0]: D AUTOLOAD\n"; $_[0]->NEXT::AUTOLOAD() }
109 sub D::DESTROY { print "$_[0]: D dtor\n"; $_[0]->NEXT::DESTROY() }
e4783b1c 110
13021a80 111 package main;
e4783b1c 112
13021a80 113 my $obj = bless {}, "D";
e4783b1c 114
13021a80 115 $obj->method(); # Calls D::method, A::method, C::method
116 $obj->missing_method(); # Calls D::AUTOLOAD, B::AUTOLOAD, C::AUTOLOAD
e4783b1c 117
13021a80 118 # Clean-up calls D::DESTROY, B::DESTROY, A::DESTROY, C::DESTROY
e4783b1c 119
120
121=head1 DESCRIPTION
122
123NEXT.pm adds a pseudoclass named C<NEXT> to any program
124that uses it. If a method C<m> calls C<$self->NEXT::m()>, the call to
125C<m> is redispatched as if the calling method had not originally been found.
126
127In other words, a call to C<$self->NEXT::m()> resumes the depth-first,
55a1c97c 128left-to-right search of C<$self>'s class hierarchy that resulted in the
129original call to C<m>.
130
131Note that this is not the same thing as C<$self->SUPER::m()>, which
132begins a new dispatch that is restricted to searching the ancestors
133of the current class. C<$self->NEXT::m()> can backtrack
134past the current class -- to look for a suitable method in other
135ancestors of C<$self> -- whereas C<$self->SUPER::m()> cannot.
e4783b1c 136
137A typical use would be in the destructors of a class hierarchy,
138as illustrated in the synopsis above. Each class in the hierarchy
139has a DESTROY method that performs some class-specific action
140and then redispatches the call up the hierarchy. As a result,
141when an object of class D is destroyed, the destructors of I<all>
142its parent classes are called (in depth-first, left-to-right order).
143
144Another typical use of redispatch would be in C<AUTOLOAD>'ed methods.
145If such a method determined that it was not able to handle a
146particular call, it might choose to redispatch that call, in the
147hope that some other C<AUTOLOAD> (above it, or to its left) might
148do better.
149
13021a80 150By default, if a redispatch attempt fails to find another method
151elsewhere in the objects class hierarchy, it quietly gives up and does
152nothing (but see L<"Enforcing redispatch">). This gracious acquiesence
153is also unlike the (generally annoying) behaviour of C<SUPER>, which
154throws an exception if it cannot redispatch.
155
e4783b1c 156Note that it is a fatal error for any method (including C<AUTOLOAD>)
13021a80 157to attempt to redispatch any method that does not have the
158same name. For example:
159
160 sub D::oops { print "oops!\n"; $_[0]->NEXT::other_method() }
161
162
163=head2 Enforcing redispatch
164
165It is possible to make C<NEXT> redispatch more demandingly (i.e. like
166C<SUPER> does), so that the redispatch throws an exception if it cannot
167find a "next" method to call.
168
169To do this, simple invoke the redispatch as:
170
171 $self->NEXT::ACTUAL::method();
172
173rather than:
174
175 $self->NEXT::method();
176
177The C<ACTUAL> tells C<NEXT> that there must actually be a next method to call,
178or it should throw an exception.
179
180C<NEXT::ACTUAL> is most commonly used in C<AUTOLOAD> methods, as a means to
181decline an C<AUTOLOAD> request, but preserve the normal exception-on-failure
182semantics:
183
184 sub AUTOLOAD {
185 if ($AUTOLOAD =~ /foo|bar/) {
186 # handle here
187 }
188 else { # try elsewhere
189 shift()->NEXT::ACTUAL::AUTOLOAD(@_);
190 }
191 }
192
193By using C<NEXT::ACTUAL>, if there is no other C<AUTOLOAD> to handle the
194method call, an exception will be thrown (as usually happens in the absence of
195a suitable C<AUTOLOAD>).
196
197
198=head2 Avoiding repetitions
199
200If C<NEXT> redispatching is used in the methods of a "diamond" class hierarchy:
201
202 # A B
203 # / \ /
204 # C D
205 # \ /
206 # E
207
208 use NEXT;
209
210 package A;
211 sub foo { print "called A::foo\n"; shift->NEXT::foo() }
212
213 package B;
214 sub foo { print "called B::foo\n"; shift->NEXT::foo() }
215
216 package C; @ISA = qw( A );
217 sub foo { print "called C::foo\n"; shift->NEXT::foo() }
218
219 package D; @ISA = qw(A B);
220 sub foo { print "called D::foo\n"; shift->NEXT::foo() }
221
222 package E; @ISA = qw(C D);
223 sub foo { print "called E::foo\n"; shift->NEXT::foo() }
224
225 E->foo();
226
227then derived classes may (re-)inherit base-class methods through two or
228more distinct paths (e.g. in the way C<E> inherits C<A::foo> twice --
229through C<C> and C<D>). In such cases, a sequence of C<NEXT> redispatches
230will invoke the multiply inherited method as many times as it is
231inherited. For example, the above code prints:
232
233 called E::foo
234 called C::foo
235 called A::foo
236 called D::foo
237 called A::foo
238 called B::foo
239
240(i.e. C<A::foo> is called twice).
241
242In some cases this I<may> be the desired effect within a diamond hierarchy,
243but in others (e.g. for destructors) it may be more appropriate to
244call each method only once during a sequence of redispatches.
245
246To cover such cases, you can redispatch methods via:
247
52138ef3 248 $self->NEXT::DISTINCT::method();
13021a80 249
250rather than:
251
252 $self->NEXT::method();
253
52138ef3 254This causes the redispatcher to only visit each distinct C<method> method
255once. That is, to skip any classes in the hierarchy that it has
256already visited during redispatch. So, for example, if the
13021a80 257previous example were rewritten:
258
259 package A;
52138ef3 260 sub foo { print "called A::foo\n"; shift->NEXT::DISTINCT::foo() }
13021a80 261
262 package B;
52138ef3 263 sub foo { print "called B::foo\n"; shift->NEXT::DISTINCT::foo() }
13021a80 264
265 package C; @ISA = qw( A );
52138ef3 266 sub foo { print "called C::foo\n"; shift->NEXT::DISTINCT::foo() }
13021a80 267
268 package D; @ISA = qw(A B);
52138ef3 269 sub foo { print "called D::foo\n"; shift->NEXT::DISTINCT::foo() }
13021a80 270
271 package E; @ISA = qw(C D);
52138ef3 272 sub foo { print "called E::foo\n"; shift->NEXT::DISTINCT::foo() }
13021a80 273
274 E->foo();
275
276then it would print:
277
278 called E::foo
279 called C::foo
280 called A::foo
281 called D::foo
282 called B::foo
283
52138ef3 284and omit the second call to C<A::foo> (since it would not be distinct
285from the first call to C<A::foo>).
13021a80 286
287Note that you can also use:
288
52138ef3 289 $self->NEXT::DISTINCT::ACTUAL::method();
13021a80 290
291or:
292
52138ef3 293 $self->NEXT::ACTUAL::DISTINCT::method();
e4783b1c 294
13021a80 295to get both unique invocation I<and> exception-on-failure.
e4783b1c 296
52138ef3 297Note that, for historical compatibility, you can also use
298C<NEXT::UNSEEN> instead of C<NEXT::DISTINCT>.
e4783b1c 299
300=head1 AUTHOR
301
302Damian Conway (damian@conway.org)
303
304=head1 BUGS AND IRRITATIONS
305
306Because it's a module, not an integral part of the interpreter, NEXT.pm
307has to guess where the surrounding call was found in the method
308look-up sequence. In the presence of diamond inheritance patterns
309it occasionally guesses wrong.
310
311It's also too slow (despite caching).
312
313Comment, suggestions, and patches welcome.
314
315=head1 COPYRIGHT
316
55a1c97c 317 Copyright (c) 2000-2001, Damian Conway. All Rights Reserved.
e4783b1c 318 This module is free software. It may be used, redistributed
55a1c97c 319 and/or modified under the same terms as Perl itself.