The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

AutoLoader::Register - A smart autoloader to be inherited by your classes

SYNOPSIS

    package MyModule;

    use AutoLoader::Register
        method1 => q{ sub {
                        my ($self, $arg) = @_;
                        $self->{$arg};
                    }},
        method2 => q{ sub {
                        my $self = shift;
                        return $self->{arg};
                    }},
        method3 => q{ sub {
                        my $self = shift;
                        print $self->method2;
                    }};

    sub new {
        my $class   = shift;
        $self       = { };
        ...
        return bless $self, $class;
    }

DESCRIPTION

Before reading on, please notice: This code is absolute ALPHA. Things may change in the future (or may not).

AutoLoader::Register is an extension to Perl's normal autoloading mechanism. Compilation of the code is delayed until one of the specified methods is actually called the first time. Once it has been called, the method is compiled into your module's namespace so that consecutive calls to it will avoid any look-up through the autoloader.

Thus the speed-penalty that is usually caused by autoloading is minimized: Your scripts start up more quickly since less code is to be compiled and during runtime each used method only has to be looked up and compiled once. You wont get much closer to optimal performance.

The module is very similar in functionality to SelfLoader and AutoSplit/AutoLoader. Unlike those it is intended only for methods (either class- or instance-methods). More to it, no reading from whatsoever filehandle is required which also avoids the necessity to parse Perl-code as SelfLoader does.

USE

It is pretty straight-forward actually:

1) SUBCLASSING

Nothing to be done here. Usually you make your class a subclass of something by adding

    use base qw(Something);

to your script. As far as AutoLoader::Register is concerned, you do not need this line since your class will automatically turn into a subclass once you include this module via use().

2) INCLUDE THE MODULE

Now include AutoLoader::Register with the use()-statement. You have to supply the methods to be autoloaded as key/value pairs. The key is the name of the method under which it should be accessible while the value a string of an anonymous Perl-subroutine is. Example:

    use AutoLoader::Register
        method1 => q{ sub {
                        my $self = shift;
                        ...
                    }},
        method2 => ... ;

Additionally, you can pass a method as code-reference. In such a case all you have to is leave away the quotes around the anonymous subroutine. This has the effect that the code is already compiled when it is passed to AutoLoader::Register:

    use AutoLoader::Register
        compiled_method => sub { print "I am already compiled\n" } ;

3) CONFIGURE THE AUTOLOADER

You can specify how your module should behave if a method is called that is not defined in your class nor managed by the autoloader. Currently four behaviours can be specified with the 'exception' option: 'warn' (but continue your program), 'croak' (spectacularly report the error and terminate the program), ignore it (the default) or a custom behaviour you specify with passing an anonymous subroutine to autoloader_configure.

For that purpose AutoLoader::Register provides a function, autoloader_configure.

    use AutoLoader::Register
        method1 => ...
        method2 => ... ;
    
    # constructor
    sub new {
        AutoLoader::Register::autoloader_configure (exception => 'warn');
        bless {}, shift;
    }

See also further below "FUNCTIONS".

4) WRITE THE CODE OF YOUR CLASS

What follows is simply what you always do when you write Perl-code. Add functions, methods, include modules, whatever...it's all up to you.

A COMPILE-TIME ONLY CLASS

Since you can even make your constructor autoloadable, you can create a class that only contains compile-time code:

    package CompileTimeClass;

    BEGIN { 
        
    our $VERSION = '0.01'; 
    use AutoLoader::Register new   => q{ sub { bless { }, shift } },
                             store => q{ sub { my $self = shift;
                                               $self->{arg} = shift } },
                             get   => q{ sub { shift->{arg} } ;
    }

Three little methods: an empty constructor, a store-method to store an arbitrary scalar and a get-method to retrieve this value.

Nothing except $VERSION gets compiled when you use() this little class in your program. It's all done on the fly and only once per method. Use the above to impress your colleagues at work.

INHERITANCE (OR NOT)

Consider you have a class Class1 that has a bunch of methods (irrelevant whether managed by AutoLoader::Register or not). Now consider that you have another Class Class2. This class should have some methods of Class1 but yet you don't want to make Class1 a superclass. You can now use AutoLoader::Cache to sort of copy methods from Class1 into your second class. For that there is the AutoLoader::Cache::get_methods_from function:

    package Class2;

    BEGIN {
        use AutoLoader::Register
                            method => ... 
                            ...    => ... ;
        AutoLoader::Register::get_methods_from ( "Class1", qw(meth1 meth2) );
    }

Think of this as inheritance among siblings.

Perhaps as a side-note: You can use AutoLoader::Register without any further arguments to it. The above example shows that this can be useful from time to time, namely if you only want a few methods from another class.

However, mark that you can load methods from any class even if this class has nothing whatsoever to do with B>AutoLoader::Register>. There are two scenarios actually:

  • Getting methods from a class not under control of AutoLoader::Register:

    The methods to be imported *must not* be supplied via autoloading.

  • Getting methods from a class managed by AutoLoader::Register:

    Can both be autoloaded methods or those hard-coded in the class.

FUNCTIONS

AutoLoader::Register comes with a few functions that are by default not exported into your class' namespace. You can do that by providing a reference to an array of functions you want to import as last argument to the use statement:

    use Register::AutoLoader
                    method1 => ... ,
                    method2 => ... ,
                    [ qw(autoloader_configure ...) ];
autoloader_configure (OPTIONS)

Currently only used to indicate what should be done in case a called method could not be autoloaded. Arguments come in key/value pairs:

  • exception => 'warn' | 'croak' | [ CODEREF, arguments ... ]

    When set to 'warn' each time a non-existing method is called, a warning message is printed, but execution of the code continues. 'croak' will give the same message but terminate your program immediately.

    CODEREF will allow you to set up a custom behaviour under such circumstances. This can be anything, beginning with your own error-messages (perhaps writing to a log-file) or more complex things. If you want to pass additional arguments to your CODEREF, pass it all as a reference to an anonymous array.

    Each handler you write will have one default argument: namely the value of $AUTOLOAD. This is a string consisting of the fully qualified method call. So if you called the method 'foo' in your class 'bar', the first argument to your handler will be the string "bar::foo".

    Example:

        # Setting up a handler with additional arguments:
        # A silly one, since it will always return 100
        my $code = sub { return $_[1] * $_[2] };
        autoloader_configure ( exception => [ $code, 10, 10 ] );
    
        # Setting up one without arguments
        my $code = sub { print "Method does not exist: $_[0]\n" }
        autoloader_configure ( exception => $code );

    As you see, you only have to give an array-ref when you actually pass additional arguments.

get_method_from (FROM, METHODS)

This will add METHODS (a simple list of strings) from the class FROM to your current class. Thus you can selectively sort of inherit the methods you want without making your class a subclass of FROM. Care is taken that no unnecessary compilation of code takes place. That means: if the any methods you want to pull are not yet compiled (perhaps because they were themselves methods given to AutoLoader::Register by the class FROM and not yet called), just a string-copy is done internally.

You can pull in methods from practically any class. So if you selectively want a few methods from MIME::Entity, no problem. Example:

    get_method_from ("MIME::Entity", "effective_type");

You do not even need to require or use the module. AutoLoader::Register does all of that for you.

NOTES

One limitation of autoloading is that autoloaded methods are not reported by UNIVERSAL::can(). AutoLoader::Register however has its own custom can() that circumvents these limitations. When you do $obj->can("method") (given that you did not define a can-method in your class) Autoloader::Cache returns the code-ref to "method" if the method has been found. If it has not been found, it calls UNIVERSAL::can() so that methods you directly define in your class are reported properly.

If you use a CODEREF to be executed on calling non-existing methods using autoloader_configure be careful when inspecting the caller-stack using caller. Since this CODEREF always is an anonymous subroutine, the code can't be executed using goto &$CODEREF. That means that in your caller-stack there should be an entry 'AutoLoader::Register'. But thus you can still distinguish between a registered method (since in such a case the method is compiled into your class) and one called on an exception.

BUGS

Any code not being in either the methods or a BEGIN (or CHECK) block seems to be NOT executed. There is not much to worry about it since you can in fact put it into a BEGIN-block or have several of those. So whenever you create a class, be sure to put vital things (such as the $VERSION package-variable) into the BEGIN-block.

Another problem seems to occur when you define to (sort-of) inner-classes in your program and put one class under control of AutoLoader::Register while at the same time trying to get_methods_from the other class.

This beast needs more testing so I guess there are a few more lying around. Whenever you happen to find one, please do not hesitate to send me a note to the email-address found further below.

THANKS

Many thanks to Mark Jason Dominus for the wealth of Perl-related information and Perl-techniques on his webside http://perl.plover.com/ .

VERSION

This is version 0.01.

AUTHOR AND COPYRIGHT

Tassilo von Parseval

<tassilo.parseval@post.rwth-aachen.de>

Copyright (c) 2001-2002 Tassilo von Parseval. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

AutoLoader

http://perl.plover.com/yak/tricks/slide073.html

1 POD Error

The following errors were encountered while parsing the POD:

Around line 314:

You forgot a '=back' before '=head1'