fix up C3.pm
[gitmo/Class-C3.git] / lib / Class / C3.pm
CommitLineData
95bebf8c 1
2package Class::C3;
3
4use strict;
5use warnings;
6
95bebf8c 7use Scalar::Util 'blessed';
8
f093ecf6 9our $VERSION = '0.14';
27195a45 10our $C3_IN_CORE;
11
e74fb2d2 12BEGIN {
13 eval { require mro };
892f8387 14 if($@) {
15 require Algorithm::C3;
16 }
17 else {
e74fb2d2 18 $C3_IN_CORE = 1;
19 }
20}
d401eda1 21
22# this is our global stash of both
23# MRO's and method dispatch tables
24# the structure basically looks like
25# this:
26#
27# $MRO{$class} = {
28# MRO => [ <class precendence list> ],
29# methods => {
30# orig => <original location of method>,
31# code => \&<ref to original method>
680100b1 32# },
33# has_overload_fallback => (1 | 0)
d401eda1 34# }
35#
f7facd7b 36our %MRO;
95bebf8c 37
d0e2efe5 38# use these for debugging ...
d401eda1 39sub _dump_MRO_table { %MRO }
d401eda1 40our $TURN_OFF_C3 = 0;
6262b4cf 41
42# state tracking for initialize()/uninitialize()
ff168601 43our $_initialized = 0;
d401eda1 44
95bebf8c 45sub import {
46 my $class = caller();
d401eda1 47 # skip if the caller is main::
48 # since that is clearly not relevant
95bebf8c 49 return if $class eq 'main';
d401eda1 50 return if $TURN_OFF_C3;
27195a45 51 if($C3_IN_CORE) {
892f8387 52 mro::set_mro_c3($class);
27195a45 53 }
d401eda1 54 # make a note to calculate $class
55 # during INIT phase
f7facd7b 56 $MRO{$class} = undef unless exists $MRO{$class};
95bebf8c 57}
58
d401eda1 59## initializers
60
d401eda1 61sub initialize {
27195a45 62 %next::METHOD_CACHE = ();
d401eda1 63 # why bother if we don't have anything ...
64 return unless keys %MRO;
27195a45 65 if($C3_IN_CORE) {
e74fb2d2 66 mro::set_mro_c3($_) for keys %MRO;
27195a45 67 }
68 else {
69 if($_initialized) {
70 uninitialize();
71 $MRO{$_} = undef foreach keys %MRO;
72 }
73 _calculate_method_dispatch_tables();
74 _apply_method_dispatch_tables();
75 $_initialized = 1;
ff168601 76 }
d401eda1 77}
78
d0e2efe5 79sub uninitialize {
80 # why bother if we don't have anything ...
5d5c86d9 81 %next::METHOD_CACHE = ();
27195a45 82 return unless keys %MRO;
83 if($C3_IN_CORE) {
e74fb2d2 84 mro::set_mro_dfs($_) for keys %MRO;
27195a45 85 }
86 else {
87 _remove_method_dispatch_tables();
88 $_initialized = 0;
89 }
d0e2efe5 90}
91
ff168601 92sub reinitialize { goto &initialize }
d0e2efe5 93
d401eda1 94## functions for applying C3 to classes
95
96sub _calculate_method_dispatch_tables {
27195a45 97 return if $C3_IN_CORE;
f4a893b2 98 my %merge_cache;
95bebf8c 99 foreach my $class (keys %MRO) {
f4a893b2 100 _calculate_method_dispatch_table($class, \%merge_cache);
95bebf8c 101 }
d401eda1 102}
103
104sub _calculate_method_dispatch_table {
27195a45 105 return if $C3_IN_CORE;
f4a893b2 106 my ($class, $merge_cache) = @_;
d401eda1 107 no strict 'refs';
f4a893b2 108 my @MRO = calculateMRO($class, $merge_cache);
d401eda1 109 $MRO{$class} = { MRO => \@MRO };
680100b1 110 my $has_overload_fallback = 0;
d401eda1 111 my %methods;
112 # NOTE:
113 # we do @MRO[1 .. $#MRO] here because it
114 # makes no sense to interogate the class
115 # which you are calculating for.
116 foreach my $local (@MRO[1 .. $#MRO]) {
680100b1 117 # if overload has tagged this module to
118 # have use "fallback", then we want to
119 # grab that value
120 $has_overload_fallback = ${"${local}::()"}
121 if defined ${"${local}::()"};
d401eda1 122 foreach my $method (grep { defined &{"${local}::$_"} } keys %{"${local}::"}) {
123 # skip if already overriden in local class
124 next unless !defined *{"${class}::$method"}{CODE};
125 $methods{$method} = {
126 orig => "${local}::$method",
127 code => \&{"${local}::$method"}
128 } unless exists $methods{$method};
95bebf8c 129 }
d401eda1 130 }
131 # now stash them in our %MRO table
680100b1 132 $MRO{$class}->{methods} = \%methods;
133 $MRO{$class}->{has_overload_fallback} = $has_overload_fallback;
d401eda1 134}
135
136sub _apply_method_dispatch_tables {
27195a45 137 return if $C3_IN_CORE;
d401eda1 138 foreach my $class (keys %MRO) {
139 _apply_method_dispatch_table($class);
140 }
95bebf8c 141}
142
d401eda1 143sub _apply_method_dispatch_table {
27195a45 144 return if $C3_IN_CORE;
d401eda1 145 my $class = shift;
146 no strict 'refs';
680100b1 147 ${"${class}::()"} = $MRO{$class}->{has_overload_fallback}
148 if $MRO{$class}->{has_overload_fallback};
d401eda1 149 foreach my $method (keys %{$MRO{$class}->{methods}}) {
150 *{"${class}::$method"} = $MRO{$class}->{methods}->{$method}->{code};
151 }
152}
153
d0e2efe5 154sub _remove_method_dispatch_tables {
27195a45 155 return if $C3_IN_CORE;
d0e2efe5 156 foreach my $class (keys %MRO) {
157 _remove_method_dispatch_table($class);
158 }
159}
160
161sub _remove_method_dispatch_table {
27195a45 162 return if $C3_IN_CORE;
d0e2efe5 163 my $class = shift;
164 no strict 'refs';
680100b1 165 delete ${"${class}::"}{"()"} if $MRO{$class}->{has_overload_fallback};
d0e2efe5 166 foreach my $method (keys %{$MRO{$class}->{methods}}) {
5dd9299c 167 delete ${"${class}::"}{$method}
168 if defined *{"${class}::${method}"}{CODE} &&
169 (*{"${class}::${method}"}{CODE} eq $MRO{$class}->{methods}->{$method}->{code});
d0e2efe5 170 }
171}
172
d401eda1 173## functions for calculating C3 MRO
174
95bebf8c 175sub calculateMRO {
f4a893b2 176 my ($class, $merge_cache) = @_;
27195a45 177 if($C3_IN_CORE) {
e74fb2d2 178 return @{mro::get_mro_linear_c3($class)};
27195a45 179 }
180 else {
181 return Algorithm::C3::merge($class, sub {
182 no strict 'refs';
183 @{$_[0] . '::ISA'};
184 }, $merge_cache);
185 }
95bebf8c 186}
187
5d5c86d9 188package # hide me from PAUSE
189 next;
190
191use strict;
192use warnings;
193
194use Scalar::Util 'blessed';
195
ac6b0914 196our $VERSION = '0.05';
5d5c86d9 197
198our %METHOD_CACHE;
199
fa91a1c7 200sub method {
27195a45 201 my $self = $_[0];
202 my $class = blessed($self) || $self;
fa91a1c7 203 my $indirect = caller() =~ /^(?:next|maybe::next)$/;
204 my $level = $indirect ? 2 : 1;
205
7bb662d7 206 my ($method_caller, $label, @label);
ac6b0914 207 while ($method_caller = (caller($level++))[3]) {
7bb662d7 208 @label = (split '::', $method_caller);
209 $label = pop @label;
210 last unless
211 $label eq '(eval)' ||
212 $label eq '__ANON__';
ac6b0914 213 }
27195a45 214
215 my $method;
216
217 # You would think we could do this, but we can't apparently :(
e74fb2d2 218 #if($Class::C3::C3_IN_CORE && mro::is_mro_c3($class)) {
27195a45 219 # $method = $class->can('SUPER::' . $label);
220 #}
221 #else {
222 my $caller = join '::' => @label;
5d5c86d9 223
27195a45 224 $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
322a5920 225
27195a45 226 my @MRO = Class::C3::calculateMRO($class);
322a5920 227
27195a45 228 my $current;
229 while ($current = shift @MRO) {
230 last if $caller eq $current;
231 }
322a5920 232
27195a45 233 no strict 'refs';
234 my $found;
235 foreach my $class (@MRO) {
236 next if (defined $Class::C3::MRO{$class} &&
237 defined $Class::C3::MRO{$class}{methods}{$label});
238 last if (defined ($found = *{$class . '::' . $label}{CODE}));
239 }
322a5920 240
27195a45 241 $found;
242 };
243 #}
fa91a1c7 244
245 return $method if $indirect;
246
247 die "No next::method '$label' found for $self" if !$method;
248
249 goto &{$method};
322a5920 250}
5d5c86d9 251
fa91a1c7 252sub can { method($_[0]) }
5d5c86d9 253
fa91a1c7 254package # hide me from PAUSE
255 maybe::next;
256
257use strict;
258use warnings;
259
260our $VERSION = '0.01';
261
262sub method { (next::method($_[0]) || return)->(@_) }
5d5c86d9 263
95bebf8c 2641;
265
266__END__
267
268=pod
269
270=head1 NAME
271
272Class::C3 - A pragma to use the C3 method resolution order algortihm
273
274=head1 SYNOPSIS
275
276 package A;
277 use Class::C3;
278 sub hello { 'A::hello' }
279
280 package B;
281 use base 'A';
282 use Class::C3;
283
284 package C;
285 use base 'A';
286 use Class::C3;
287
288 sub hello { 'C::hello' }
289
290 package D;
291 use base ('B', 'C');
292 use Class::C3;
293
294 # Classic Diamond MI pattern
d401eda1 295 # <A>
296 # / \
297 # <B> <C>
298 # \ /
299 # <D>
95bebf8c 300
301 package main;
2ffffc6d 302
303 # initializez the C3 module
304 # (formerly called in INIT)
305 Class::C3::initialize();
95bebf8c 306
307 print join ', ' => Class::C3::calculateMRO('Diamond_D') # prints D, B, C, A
308
309 print D->hello() # prints 'C::hello' instead of the standard p5 'A::hello'
310
311 D->can('hello')->(); # can() also works correctly
312 UNIVERSAL::can('D', 'hello'); # as does UNIVERSAL::can()
313
314=head1 DESCRIPTION
315
2ffffc6d 316This is pragma to change Perl 5's standard method resolution order from depth-first left-to-right
317(a.k.a - pre-order) to the more sophisticated C3 method resolution order.
95bebf8c 318
319=head2 What is C3?
320
321C3 is the name of an algorithm which aims to provide a sane method resolution order under multiple
322inheritence. It was first introduced in the langauge Dylan (see links in the L<SEE ALSO> section),
323and then later adopted as the prefered MRO (Method Resolution Order) for the new-style classes in
324Python 2.3. Most recently it has been adopted as the 'canonical' MRO for Perl 6 classes, and the
325default MRO for Parrot objects as well.
326
327=head2 How does C3 work.
328
329C3 works by always preserving local precendence ordering. This essentially means that no class will
330appear before any of it's subclasses. Take the classic diamond inheritence pattern for instance:
331
d401eda1 332 <A>
333 / \
334 <B> <C>
335 \ /
336 <D>
95bebf8c 337
338The standard Perl 5 MRO would be (D, B, A, C). The result being that B<A> appears before B<C>, even
339though B<C> is the subclass of B<A>. The C3 MRO algorithm however, produces the following MRO
340(D, B, C, A), which does not have this same issue.
341
342This example is fairly trival, for more complex examples and a deeper explaination, see the links in
343the L<SEE ALSO> section.
344
345=head2 How does this module work?
346
2ffffc6d 347This module uses a technique similar to Perl 5's method caching. When C<Class::C3::initialize> is
348called, this module calculates the MRO of all the classes which called C<use Class::C3>. It then
349gathers information from the symbol tables of each of those classes, and builds a set of method
350aliases for the correct dispatch ordering. Once all these C3-based method tables are created, it
351then adds the method aliases into the local classes symbol table.
95bebf8c 352
353The end result is actually classes with pre-cached method dispatch. However, this caching does not
354do well if you start changing your C<@ISA> or messing with class symbol tables, so you should consider
355your classes to be effectively closed. See the L<CAVEATS> section for more details.
356
d401eda1 357=head1 OPTIONAL LOWERCASE PRAGMA
358
359This release also includes an optional module B<c3> in the F<opt/> folder. I did not include this in
360the regular install since lowercase module names are considered I<"bad"> by some people. However I
361think that code looks much nicer like this:
362
363 package MyClass;
364 use c3;
365
366The the more clunky:
367
368 package MyClass;
369 use Class::C3;
370
371But hey, it's your choice, thats why it is optional.
372
95bebf8c 373=head1 FUNCTIONS
374
375=over 4
376
377=item B<calculateMRO ($class)>
378
379Given a C<$class> this will return an array of class names in the proper C3 method resolution order.
380
d401eda1 381=item B<initialize>
382
2ffffc6d 383This B<must be called> to initalize the C3 method dispatch tables, this module B<will not work> if
5f01eb5f 384you do not do this. It is advised to do this as soon as possible B<after> loading any classes which
385use C3. Here is a quick code example:
386
387 package Foo;
388 use Class::C3;
389 # ... Foo methods here
390
391 package Bar;
392 use Class::C3;
393 use base 'Foo';
394 # ... Bar methods here
395
396 package main;
397
398 Class::C3::initialize(); # now it is safe to use Foo and Bar
2ffffc6d 399
400This function used to be called automatically for you in the INIT phase of the perl compiler, but
401that lead to warnings if this module was required at runtime. After discussion with my user base
402(the L<DBIx::Class> folks), we decided that calling this in INIT was more of an annoyance than a
403convience. I apologize to anyone this causes problems for (although i would very suprised if I had
404any other users other than the L<DBIx::Class> folks). The simplest solution of course is to define
405your own INIT method which calls this function.
d401eda1 406
407NOTE:
ff168601 408
409If C<initialize> detects that C<initialize> has already been executed, it will L</uninitialize> and
410clear the MRO cache first.
d0e2efe5 411
412=item B<uninitialize>
413
414Calling this function results in the removal of all cached methods, and the restoration of the old Perl 5
415style dispatch order (depth-first, left-to-right).
416
417=item B<reinitialize>
418
ff168601 419This is an alias for L</initialize> above.
d401eda1 420
95bebf8c 421=back
422
5d5c86d9 423=head1 METHOD REDISPATCHING
424
425It is always useful to be able to re-dispatch your method call to the "next most applicable method". This
426module provides a pseudo package along the lines of C<SUPER::> or C<NEXT::> which will re-dispatch the
427method along the C3 linearization. This is best show with an examples.
428
429 # a classic diamond MI pattern ...
430 <A>
431 / \
432 <B> <C>
433 \ /
434 <D>
435
436 package A;
437 use c3;
438 sub foo { 'A::foo' }
439
440 package B;
441 use base 'A';
442 use c3;
443 sub foo { 'B::foo => ' . (shift)->next::method() }
444
445 package B;
446 use base 'A';
447 use c3;
448 sub foo { 'C::foo => ' . (shift)->next::method() }
449
450 package D;
451 use base ('B', 'C');
452 use c3;
453 sub foo { 'D::foo => ' . (shift)->next::method() }
454
455 print D->foo; # prints out "D::foo => B::foo => C::foo => A::foo"
456
457A few things to note. First, we do not require you to add on the method name to the C<next::method>
458call (this is unlike C<NEXT::> and C<SUPER::> which do require that). This helps to enforce the rule
459that you cannot dispatch to a method of a different name (this is how C<NEXT::> behaves as well).
460
461The next thing to keep in mind is that you will need to pass all arguments to C<next::method> it can
462not automatically use the current C<@_>.
463
322a5920 464If C<next::method> cannot find a next method to re-dispatch the call to, it will throw an exception.
465You can use C<next::can> to see if C<next::method> will succeed before you call it like so:
466
467 $self->next::method(@_) if $self->next::can;
468
fa91a1c7 469Additionally, you can use C<maybe::next::method> as a shortcut to only call the next method if it exists.
470The previous example could be simply written as:
471
472 $self->maybe::next::method(@_);
322a5920 473
2ffffc6d 474There are some caveats about using C<next::method>, see below for those.
95bebf8c 475
2ffffc6d 476=head1 CAVEATS
95bebf8c 477
2ffffc6d 478This module used to be labeled as I<experimental>, however it has now been pretty heavily tested by
479the good folks over at L<DBIx::Class> and I am confident this module is perfectly usable for
480whatever your needs might be.
95bebf8c 481
2ffffc6d 482But there are still caveats, so here goes ...
95bebf8c 483
484=over 4
485
486=item Use of C<SUPER::>.
487
488The idea of C<SUPER::> under multiple inheritence is ambigious, and generally not recomended anyway.
489However, it's use in conjuntion with this module is very much not recommended, and in fact very
5d5c86d9 490discouraged. The recommended approach is to instead use the supplied C<next::method> feature, see
491more details on it's usage above.
95bebf8c 492
493=item Changing C<@ISA>.
494
495It is the author's opinion that changing C<@ISA> at runtime is pure insanity anyway. However, people
496do it, so I must caveat. Any changes to the C<@ISA> will not be reflected in the MRO calculated by this
d0e2efe5 497module, and therefor probably won't even show up. If you do this, you will need to call C<reinitialize>
498in order to recalulate B<all> method dispatch tables. See the C<reinitialize> documentation and an example
499in F<t/20_reinitialize.t> for more information.
95bebf8c 500
501=item Adding/deleting methods from class symbol tables.
502
2ffffc6d 503This module calculates the MRO for each requested class by interogatting the symbol tables of said classes.
504So any symbol table manipulation which takes place after our INIT phase is run will not be reflected in
505the calculated MRO. Just as with changing the C<@ISA>, you will need to call C<reinitialize> for any
506changes you make to take effect.
95bebf8c 507
2ffffc6d 508=item Calling C<next::method> from methods defined outside the class
95bebf8c 509
2ffffc6d 510There is an edge case when using C<next::method> from within a subroutine which was created in a different
511module than the one it is called from. It sounds complicated, but it really isn't. Here is an example which
512will not work correctly:
15eeb546 513
2ffffc6d 514 *Foo::foo = sub { (shift)->next::method(@_) };
515
516The problem exists because the anonymous subroutine being assigned to the glob C<*Foo::foo> will show up
517in the call stack as being called C<__ANON__> and not C<foo> as you might expect. Since C<next::method>
518uses C<caller> to find the name of the method it was called in, it will fail in this case.
15eeb546 519
2ffffc6d 520But fear not, there is a simple solution. The module C<Sub::Name> will reach into the perl internals and
521assign a name to an anonymous subroutine for you. Simply do this:
522
523 use Sub::Name 'subname';
524 *Foo::foo = subname 'Foo::foo' => sub { (shift)->next::method(@_) };
15eeb546 525
2ffffc6d 526and things will Just Work. Of course this is not always possible to do, but to be honest, I just can't
527manage to find a workaround for it, so until someone gives me a working patch this will be a known
528limitation of this module.
15eeb546 529
5d5c86d9 530=back
15eeb546 531
5d5c86d9 532=head1 CODE COVERAGE
15eeb546 533
ac6b0914 534I use B<Devel::Cover> to test the code coverage of my tests, below is the B<Devel::Cover> report on this
535module's test suite.
5d5c86d9 536
537 ---------------------------- ------ ------ ------ ------ ------ ------ ------
538 File stmt bran cond sub pod time total
539 ---------------------------- ------ ------ ------ ------ ------ ------ ------
58f0eafe 540 Class/C3.pm 98.3 84.4 80.0 96.2 100.0 98.4 94.4
5d5c86d9 541 ---------------------------- ------ ------ ------ ------ ------ ------ ------
58f0eafe 542 Total 98.3 84.4 80.0 96.2 100.0 98.4 94.4
5d5c86d9 543 ---------------------------- ------ ------ ------ ------ ------ ------ ------
15eeb546 544
95bebf8c 545=head1 SEE ALSO
546
547=head2 The original Dylan paper
548
549=over 4
550
551=item L<http://www.webcom.com/haahr/dylan/linearization-oopsla96.html>
552
553=back
554
555=head2 The prototype Perl 6 Object Model uses C3
556
557=over 4
558
559=item L<http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/>
560
561=back
562
563=head2 Parrot now uses C3
564
565=over 4
566
567=item L<http://aspn.activestate.com/ASPN/Mail/Message/perl6-internals/2746631>
568
569=item L<http://use.perl.org/~autrijus/journal/25768>
570
571=back
572
573=head2 Python 2.3 MRO related links
574
575=over 4
576
577=item L<http://www.python.org/2.3/mro.html>
578
579=item L<http://www.python.org/2.2.2/descrintro.html#mro>
580
581=back
582
583=head2 C3 for TinyCLOS
584
585=over 4
586
587=item L<http://www.call-with-current-continuation.org/eggs/c3.html>
588
589=back
590
bad9dc59 591=head1 ACKNOWLEGEMENTS
592
593=over 4
594
595=item Thanks to Matt S. Trout for using this module in his module L<DBIx::Class>
596and finding many bugs and providing fixes.
597
598=item Thanks to Justin Guenther for making C<next::method> more robust by handling
599calls inside C<eval> and anon-subs.
600
f480cda1 601=item Thanks to Robert Norris for adding support for C<next::can> and
602C<maybe::next::method>.
603
bad9dc59 604=back
605
95bebf8c 606=head1 AUTHOR
607
d401eda1 608Stevan Little, E<lt>stevan@iinteractive.comE<gt>
95bebf8c 609
6262b4cf 610Brandon L. Black, E<lt>blblack@gmail.comE<gt>
611
95bebf8c 612=head1 COPYRIGHT AND LICENSE
613
08c29211 614Copyright 2005, 2006 by Infinity Interactive, Inc.
95bebf8c 615
616L<http://www.iinteractive.com>
617
618This library is free software; you can redistribute it and/or modify
619it under the same terms as Perl itself.
620
f4a893b2 621=cut