-Class::C3 version 0.18
-===========================
+NAME
+ Class::C3 - A pragma to use the C3 method resolution order algortihm
-INSTALLATION
+SYNOPSIS
+ package A;
+ use Class::C3;
+ sub hello { 'A::hello' }
-To install this module type the following:
+ package B;
+ use base 'A';
+ use Class::C3;
- perl Makefile.PL
- make
- make test
- make install
+ package C;
+ use base 'A';
+ use Class::C3;
-DEPENDENCIES
+ sub hello { 'C::hello' }
-This module requires these other modules and libraries:
+ package D;
+ use base ('B', 'C');
+ use Class::C3;
- Algorithm::C3 0.06
- Scalar::Util 1.10
+ # Classic Diamond MI pattern
+ # <A>
+ # / \
+ # <B> <C>
+ # \ /
+ # <D>
-Additionally, this module will optionally take advantage of
-these if installed:
+ package main;
+
+ # initializez the C3 module
+ # (formerly called in INIT)
+ Class::C3::initialize();
- perl 5.9.5
- Class::C3::XS 0.04
+ print join ', ' => Class::C3::calculateMRO('Diamond_D') # prints D, B, C, A
-COPYRIGHT AND LICENCE
+ print D->hello() # prints 'C::hello' instead of the standard p5 'A::hello'
+
+ D->can('hello')->(); # can() also works correctly
+ UNIVERSAL::can('D', 'hello'); # as does UNIVERSAL::can()
-Copyright (C) 2005, 2006 Infinity Interactive, Inc.
+DESCRIPTION
+ This is pragma to change Perl 5's standard method resolution order from
+ depth-first left-to-right (a.k.a - pre-order) to the more sophisticated
+ C3 method resolution order.
-http://www.iinteractive.com
+ What is C3?
+ C3 is the name of an algorithm which aims to provide a sane method
+ resolution order under multiple inheritence. It was first introduced in
+ the langauge Dylan (see links in the "SEE ALSO" section), and then later
+ adopted as the prefered MRO (Method Resolution Order) for the new-style
+ classes in Python 2.3. Most recently it has been adopted as the
+ 'canonical' MRO for Perl 6 classes, and the default MRO for Parrot
+ objects as well.
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
+ How does C3 work.
+ C3 works by always preserving local precendence ordering. This
+ essentially means that no class will appear before any of it's
+ subclasses. Take the classic diamond inheritence pattern for instance:
+
+ <A>
+ / \
+ <B> <C>
+ \ /
+ <D>
+
+ The standard Perl 5 MRO would be (D, B, A, C). The result being that A
+ appears before C, even though C is the subclass of A. The C3 MRO
+ algorithm however, produces the following MRO (D, B, C, A), which does
+ not have this same issue.
+
+ This example is fairly trival, for more complex examples and a deeper
+ explaination, see the links in the "SEE ALSO" section.
+
+ How does this module work?
+ This module uses a technique similar to Perl 5's method caching. When
+ "Class::C3::initialize" is called, this module calculates the MRO of all
+ the classes which called "use Class::C3". It then gathers information
+ from the symbol tables of each of those classes, and builds a set of
+ method aliases for the correct dispatch ordering. Once all these
+ C3-based method tables are created, it then adds the method aliases into
+ the local classes symbol table.
+
+ The end result is actually classes with pre-cached method dispatch.
+ However, this caching does not do well if you start changing your @ISA
+ or messing with class symbol tables, so you should consider your classes
+ to be effectively closed. See the CAVEATS section for more details.
+
+OPTIONAL LOWERCASE PRAGMA
+ This release also includes an optional module c3 in the opt/ folder. I
+ did not include this in the regular install since lowercase module names
+ are considered *"bad"* by some people. However I think that code looks
+ much nicer like this:
+
+ package MyClass;
+ use c3;
+
+ The the more clunky:
+
+ package MyClass;
+ use Class::C3;
+
+ But hey, it's your choice, thats why it is optional.
+
+FUNCTIONS
+ calculateMRO ($class)
+ Given a $class this will return an array of class names in the
+ proper C3 method resolution order.
+
+ initialize
+ This must be called to initalize the C3 method dispatch tables, this
+ module will not work if you do not do this. It is advised to do this
+ as soon as possible after loading any classes which use C3. Here is
+ a quick code example:
+
+ package Foo;
+ use Class::C3;
+ # ... Foo methods here
+
+ package Bar;
+ use Class::C3;
+ use base 'Foo';
+ # ... Bar methods here
+
+ package main;
+
+ Class::C3::initialize(); # now it is safe to use Foo and Bar
+
+ This function used to be called automatically for you in the INIT
+ phase of the perl compiler, but that lead to warnings if this module
+ was required at runtime. After discussion with my user base (the
+ DBIx::Class folks), we decided that calling this in INIT was more of
+ an annoyance than a convience. I apologize to anyone this causes
+ problems for (although i would very suprised if I had any other
+ users other than the DBIx::Class folks). The simplest solution of
+ course is to define your own INIT method which calls this function.
+
+ NOTE:
+
+ If "initialize" detects that "initialize" has already been executed,
+ it will "uninitialize" and clear the MRO cache first.
+
+ uninitialize
+ Calling this function results in the removal of all cached methods,
+ and the restoration of the old Perl 5 style dispatch order
+ (depth-first, left-to-right).
+
+ reinitialize
+ This is an alias for "initialize" above.
+
+METHOD REDISPATCHING
+ It is always useful to be able to re-dispatch your method call to the
+ "next most applicable method". This module provides a pseudo package
+ along the lines of "SUPER::" or "NEXT::" which will re-dispatch the
+ method along the C3 linearization. This is best show with an examples.
+
+ # a classic diamond MI pattern ...
+ <A>
+ / \
+ <B> <C>
+ \ /
+ <D>
+
+ package A;
+ use c3;
+ sub foo { 'A::foo' }
+
+ package B;
+ use base 'A';
+ use c3;
+ sub foo { 'B::foo => ' . (shift)->next::method() }
+
+ package B;
+ use base 'A';
+ use c3;
+ sub foo { 'C::foo => ' . (shift)->next::method() }
+
+ package D;
+ use base ('B', 'C');
+ use c3;
+ sub foo { 'D::foo => ' . (shift)->next::method() }
+
+ print D->foo; # prints out "D::foo => B::foo => C::foo => A::foo"
+
+ A few things to note. First, we do not require you to add on the method
+ name to the "next::method" call (this is unlike "NEXT::" and "SUPER::"
+ which do require that). This helps to enforce the rule that you cannot
+ dispatch to a method of a different name (this is how "NEXT::" behaves
+ as well).
+
+ The next thing to keep in mind is that you will need to pass all
+ arguments to "next::method" it can not automatically use the current @_.
+
+ If "next::method" cannot find a next method to re-dispatch the call to,
+ it will throw an exception. You can use "next::can" to see if
+ "next::method" will succeed before you call it like so:
+
+ $self->next::method(@_) if $self->next::can;
+
+ Additionally, you can use "maybe::next::method" as a shortcut to only
+ call the next method if it exists. The previous example could be simply
+ written as:
+
+ $self->maybe::next::method(@_);
+
+ There are some caveats about using "next::method", see below for those.
+
+CAVEATS
+ This module used to be labeled as *experimental*, however it has now
+ been pretty heavily tested by the good folks over at DBIx::Class and I
+ am confident this module is perfectly usable for whatever your needs
+ might be.
+
+ But there are still caveats, so here goes ...
+
+ Use of "SUPER::".
+ The idea of "SUPER::" under multiple inheritence is ambigious, and
+ generally not recomended anyway. However, it's use in conjuntion
+ with this module is very much not recommended, and in fact very
+ discouraged. The recommended approach is to instead use the supplied
+ "next::method" feature, see more details on it's usage above.
+
+ Changing @ISA.
+ It is the author's opinion that changing @ISA at runtime is pure
+ insanity anyway. However, people do it, so I must caveat. Any
+ changes to the @ISA will not be reflected in the MRO calculated by
+ this module, and therefor probably won't even show up. If you do
+ this, you will need to call "reinitialize" in order to recalulate
+ all method dispatch tables. See the "reinitialize" documentation and
+ an example in t/20_reinitialize.t for more information.
+
+ Adding/deleting methods from class symbol tables.
+ This module calculates the MRO for each requested class by
+ interogatting the symbol tables of said classes. So any symbol table
+ manipulation which takes place after our INIT phase is run will not
+ be reflected in the calculated MRO. Just as with changing the @ISA,
+ you will need to call "reinitialize" for any changes you make to
+ take effect.
+
+ Calling "next::method" from methods defined outside the class
+ There is an edge case when using "next::method" from within a
+ subroutine which was created in a different module than the one it
+ is called from. It sounds complicated, but it really isn't. Here is
+ an example which will not work correctly:
+
+ *Foo::foo = sub { (shift)->next::method(@_) };
+
+ The problem exists because the anonymous subroutine being assigned
+ to the glob *Foo::foo will show up in the call stack as being called
+ "__ANON__" and not "foo" as you might expect. Since "next::method"
+ uses "caller" to find the name of the method it was called in, it
+ will fail in this case.
+
+ But fear not, there is a simple solution. The module "Sub::Name"
+ will reach into the perl internals and assign a name to an anonymous
+ subroutine for you. Simply do this:
+
+ use Sub::Name 'subname';
+ *Foo::foo = subname 'Foo::foo' => sub { (shift)->next::method(@_) };
+
+ and things will Just Work. Of course this is not always possible to
+ do, but to be honest, I just can't manage to find a workaround for
+ it, so until someone gives me a working patch this will be a known
+ limitation of this module.
+
+COMPATIBILITY
+ If your software requires Perl 5.9.5 or higher, you do not need
+ Class::C3, you can simply "use mro 'c3'", and not worry about
+ "initialize()", avoid some of the above caveats, and get the best
+ possible performance. See mro for more details.
+
+ If your software is meant to work on earlier Perls, use Class::C3 as
+ documented here. Class::C3 will detect Perl 5.9.5+ and take advantage of
+ the core support when available.
+
+Class::C3::XS
+ This module will load Class::C3::XS if it's installed and you are
+ running on a Perl version older than 5.9.5. Installing this is
+ recommended when possible, as it results in significant performance
+ improvements (but unlike the 5.9.5+ core support, it still has all of
+ the same caveats as Class::C3).
+
+CODE COVERAGE
+ Devel::Cover was reporting 94.4% overall test coverage earlier in this
+ module's life. Currently, the test suite does things that break under
+ coverage testing, but it is fair to assume the coverage is still close
+ to that value.
+
+SEE ALSO
+ The original Dylan paper
+ <http://www.webcom.com/haahr/dylan/linearization-oopsla96.html>
+
+ The prototype Perl 6 Object Model uses C3
+ <http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/>
+
+ Parrot now uses C3
+ <http://aspn.activestate.com/ASPN/Mail/Message/perl6-internals/2746631>
+ <http://use.perl.org/~autrijus/journal/25768>
+
+ Python 2.3 MRO related links
+ <http://www.python.org/2.3/mro.html>
+ <http://www.python.org/2.2.2/descrintro.html#mro>
+
+ C3 for TinyCLOS
+ <http://www.call-with-current-continuation.org/eggs/c3.html>
+
+ACKNOWLEGEMENTS
+ Thanks to Matt S. Trout for using this module in his module DBIx::Class
+ and finding many bugs and providing fixes.
+ Thanks to Justin Guenther for making "next::method" more robust by
+ handling calls inside "eval" and anon-subs.
+ Thanks to Robert Norris for adding support for "next::can" and
+ "maybe::next::method".
+
+AUTHOR
+ Stevan Little, <stevan@iinteractive.com>
+
+ Brandon L. Black, <blblack@gmail.com>
+
+COPYRIGHT AND LICENSE
+ Copyright 2005, 2006 by Infinity Interactive, Inc.
+
+ <http://www.iinteractive.com>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as Perl itself.