summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/mro.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/mro.pm')
-rw-r--r--Master/tlpkg/tlperl/lib/mro.pm379
1 files changed, 379 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/mro.pm b/Master/tlpkg/tlperl/lib/mro.pm
new file mode 100644
index 00000000000..f580bdadf39
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/mro.pm
@@ -0,0 +1,379 @@
+# mro.pm
+#
+# Copyright (c) 2007 Brandon L Black
+# Copyright (c) 2008,2009 Larry Wall and others
+#
+# You may distribute under the terms of either the GNU General Public
+# License or the Artistic License, as specified in the README file.
+#
+package mro;
+use strict;
+use warnings;
+
+# mro.pm versions < 1.00 reserved for MRO::Compat
+# for partial back-compat to 5.[68].x
+our $VERSION = '1.02';
+
+sub import {
+ mro::set_mro(scalar(caller), $_[1]) if $_[1];
+}
+
+package # hide me from PAUSE
+ next;
+
+sub can { mro::_nextcan($_[0], 0) }
+
+sub method {
+ my $method = mro::_nextcan($_[0], 1);
+ goto &$method;
+}
+
+package # hide me from PAUSE
+ maybe::next;
+
+sub method {
+ my $method = mro::_nextcan($_[0], 0);
+ goto &$method if defined $method;
+ return;
+}
+
+require XSLoader;
+XSLoader::load('mro', $VERSION);
+
+1;
+
+__END__
+
+=head1 NAME
+
+mro - Method Resolution Order
+
+=head1 SYNOPSIS
+
+ use mro; # enables next::method and friends globally
+
+ use mro 'dfs'; # enable DFS MRO for this class (Perl default)
+ use mro 'c3'; # enable C3 MRO for this class
+
+=head1 DESCRIPTION
+
+The "mro" namespace provides several utilities for dealing
+with method resolution order and method caching in general.
+
+These interfaces are only available in Perl 5.9.5 and higher.
+See L<MRO::Compat> on CPAN for a mostly forwards compatible
+implementation for older Perls.
+
+=head1 OVERVIEW
+
+It's possible to change the MRO of a given class either by using C<use
+mro> as shown in the synopsis, or by using the L</mro::set_mro> function
+below.
+
+The special methods C<next::method>, C<next::can>, and
+C<maybe::next::method> are not available until this C<mro> module
+has been loaded via C<use> or C<require>.
+
+=head1 The C3 MRO
+
+In addition to the traditional Perl default MRO (depth first
+search, called C<DFS> here), Perl now offers the C3 MRO as
+well. Perl's support for C3 is based on the work done in
+Stevan Little's module L<Class::C3>, and most of the C3-related
+documentation here is ripped directly from there.
+
+=head2 What is C3?
+
+C3 is the name of an algorithm which aims to provide a sane method
+resolution order under multiple inheritance. It was first introduced in
+the language Dylan (see links in the L</"SEE ALSO"> section), and then
+later adopted as the preferred 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.
+
+=head2 How does C3 work
+
+C3 works by always preserving local precedence ordering. This essentially
+means that no class will appear before any of its subclasses. Take, for
+instance, the classic diamond inheritance pattern:
+
+ <A>
+ / \
+ <B> <C>
+ \ /
+ <D>
+
+The standard Perl 5 MRO would be (D, B, A, C). The result being that B<A>
+appears before B<C>, even though B<C> is the subclass of B<A>. The C3 MRO
+algorithm however, produces the following order: (D, B, C, A), which does
+not have this issue.
+
+This example is fairly trivial; for more complex cases and a deeper
+explanation, see the links in the L</"SEE ALSO"> section.
+
+=head1 Functions
+
+=head2 mro::get_linear_isa($classname[, $type])
+
+Returns an arrayref which is the linearized MRO of the given class.
+Uses whichever MRO is currently in effect for that class by default,
+or the given MRO (either C<c3> or C<dfs> if specified as C<$type>).
+
+The linearized MRO of a class is an ordered array of all of the
+classes one would search when resolving a method on that class,
+starting with the class itself.
+
+If the requested class doesn't yet exist, this function will still
+succeed, and return C<[ $classname ]>
+
+Note that C<UNIVERSAL> (and any members of C<UNIVERSAL>'s MRO) are not
+part of the MRO of a class, even though all classes implicitly inherit
+methods from C<UNIVERSAL> and its parents.
+
+=head2 mro::set_mro ($classname, $type)
+
+Sets the MRO of the given class to the C<$type> argument (either
+C<c3> or C<dfs>).
+
+=head2 mro::get_mro($classname)
+
+Returns the MRO of the given class (either C<c3> or C<dfs>).
+
+=head2 mro::get_isarev($classname)
+
+Gets the C<mro_isarev> for this class, returned as an
+arrayref of class names. These are every class that "isa"
+the given class name, even if the isa relationship is
+indirect. This is used internally by the MRO code to
+keep track of method/MRO cache invalidations.
+
+Currently, this list only grows, it never shrinks. This
+was a performance consideration (properly tracking and
+deleting isarev entries when someone removes an entry
+from an C<@ISA> is costly, and it doesn't happen often
+anyways). The fact that a class which no longer truly
+"isa" this class at runtime remains on the list should be
+considered a quirky implementation detail which is subject
+to future change. It shouldn't be an issue as long as
+you're looking at this list for the same reasons the
+core code does: as a performance optimization
+over having to search every class in existence.
+
+As with C<mro::get_mro> above, C<UNIVERSAL> is special.
+C<UNIVERSAL> (and parents') isarev lists do not include
+every class in existence, even though all classes are
+effectively descendants for method inheritance purposes.
+
+=head2 mro::is_universal($classname)
+
+Returns a boolean status indicating whether or not
+the given classname is either C<UNIVERSAL> itself,
+or one of C<UNIVERSAL>'s parents by C<@ISA> inheritance.
+
+Any class for which this function returns true is
+"universal" in the sense that all classes potentially
+inherit methods from it.
+
+For similar reasons to C<isarev> above, this flag is
+permanent. Once it is set, it does not go away, even
+if the class in question really isn't universal anymore.
+
+=head2 mro::invalidate_all_method_caches()
+
+Increments C<PL_sub_generation>, which invalidates method
+caching in all packages.
+
+=head2 mro::method_changed_in($classname)
+
+Invalidates the method cache of any classes dependent on the
+given class. This is not normally necessary. The only
+known case where pure perl code can confuse the method
+cache is when you manually install a new constant
+subroutine by using a readonly scalar value, like the
+internals of L<constant> do. If you find another case,
+please report it so we can either fix it or document
+the exception here.
+
+=head2 mro::get_pkg_gen($classname)
+
+Returns an integer which is incremented every time a
+real local method in the package C<$classname> changes,
+or the local C<@ISA> of C<$classname> is modified.
+
+This is intended for authors of modules which do lots
+of class introspection, as it allows them to very quickly
+check if anything important about the local properties
+of a given class have changed since the last time they
+looked. It does not increment on method/C<@ISA>
+changes in superclasses.
+
+It's still up to you to seek out the actual changes,
+and there might not actually be any. Perhaps all
+of the changes since you last checked cancelled each
+other out and left the package in the state it was in
+before.
+
+This integer normally starts off at a value of C<1>
+when a package stash is instantiated. Calling it
+on packages whose stashes do not exist at all will
+return C<0>. If a package stash is completely
+deleted (not a normal occurence, but it can happen
+if someone does something like C<undef %PkgName::>),
+the number will be reset to either C<0> or C<1>,
+depending on how completely package was wiped out.
+
+=head2 next::method
+
+This is somewhat like C<SUPER>, but it uses the C3 method
+resolution order to get better consistency in multiple
+inheritance situations. Note that while inheritance in
+general follows whichever MRO is in effect for the
+given class, C<next::method> only uses the C3 MRO.
+
+One generally uses it like so:
+
+ sub some_method {
+ my $self = shift;
+ my $superclass_answer = $self->next::method(@_);
+ return $superclass_answer + 1;
+ }
+
+Note that you don't (re-)specify the method name.
+It forces you to always use the same method name
+as the method you started in.
+
+It can be called on an object or a class, of course.
+
+The way it resolves which actual method to call is:
+
+=over 4
+
+=item 1
+
+First, it determines the linearized C3 MRO of
+the object or class it is being called on.
+
+=item 2
+
+Then, it determines the class and method name
+of the context it was invoked from.
+
+=item 3
+
+Finally, it searches down the C3 MRO list until
+it reaches the contextually enclosing class, then
+searches further down the MRO list for the next
+method with the same name as the contextually
+enclosing method.
+
+=back
+
+Failure to find a next method will result in an
+exception being thrown (see below for alternatives).
+
+This is substantially different than the behavior
+of C<SUPER> under complex multiple inheritance.
+(This becomes obvious when one realizes that the
+common superclasses in the C3 linearizations of
+a given class and one of its parents will not
+always be ordered the same for both.)
+
+B<Caveat>: Calling C<next::method> from methods defined outside the class:
+
+There is an edge case when using C<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
+C<*Foo::foo> glob will show up in the call stack as being called
+C<__ANON__> and not C<foo> as you might expect. Since C<next::method> uses
+C<caller> to find the name of the method it was called in, it will fail in
+this case.
+
+But fear not, there's a simple solution. The module C<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.
+
+=head2 next::can
+
+This is similar to C<next::method>, but just returns either a code
+reference or C<undef> to indicate that no further methods of this name
+exist.
+
+=head2 maybe::next::method
+
+In simple cases, it is equivalent to:
+
+ $self->next::method(@_) if $self->next::can;
+
+But there are some cases where only this solution
+works (like C<goto &maybe::next::method>);
+
+=head1 SEE ALSO
+
+=head2 The original Dylan paper
+
+=over 4
+
+=item L<http://www.webcom.com/haahr/dylan/linearization-oopsla96.html>
+
+=back
+
+=head2 Pugs
+
+The Pugs prototype Perl 6 Object Model uses C3
+
+=head2 Parrot
+
+Parrot now uses C3
+
+=over 4
+
+=item L<http://aspn.activestate.com/ASPN/Mail/Message/perl6-internals/2746631>
+
+=item L<http://use.perl.org/~autrijus/journal/25768>
+
+=back
+
+=head2 Python 2.3 MRO related links
+
+=over 4
+
+=item L<http://www.python.org/2.3/mro.html>
+
+=item L<http://www.python.org/2.2.2/descrintro.html#mro>
+
+=back
+
+=head2 C3 for TinyCLOS
+
+=over 4
+
+=item L<http://www.call-with-current-continuation.org/eggs/c3.html>
+
+=back
+
+=head2 Class::C3
+
+=over 4
+
+=item L<Class::C3>
+
+=back
+
+=head1 AUTHOR
+
+Brandon L. Black, E<lt>blblack@gmail.comE<gt>
+
+Based on Stevan Little's L<Class::C3>
+
+=cut