Perl does not require you to declare every function before you call it. Perl will happily attempt to call a function even if it doesn't exist. Consider the program:
When you run it, Perl will throw an exception due to the call to the undefined function bake_pie()
.
Now add a function called AUTOLOAD()
:
When you run the program now, nothing obvious will happen. Perl will call a function named AUTOLOAD()
in a package--if it exists--whenever normal dispatch fails. Change the AUTOLOAD()
to emit a message:
... to demonstrate that it gets called.
The AUTOLOAD()
function receives the arguments passed to the undefined function in @_
directly and the name of the undefined function is available in the package global $AUTOLOAD
. Manipulate these arguments as you like:
The our
declaration (our) scopes $AUTOLOAD
to the function body. The variable contains the fully-qualified name of the undefined function (in this case, main::bake_pie
). Remove the package name with a regular expression (regex):
Whatever AUTOLOAD()
returns, the original call receives:
So far, these examples have merely intercepted calls to undefined functions. You have other options.
A common pattern in OO programming (moose) is to delegate or proxy certain methods in one object to another, often contained in or otherwise accessible from the former. A logging proxy can help with debugging:
This AUTOLOAD()
logs the method call. Then it dereferences the proxied object from a blessed scalar reference, extracts the name of the undefined method, then invokes that method on the proxied object with the provided parameters.
This double dispatch is easy to write but inefficient. Every method call on the proxy must fail normal dispatch to end up in AUTOLOAD()
. Pay that penalty only once by installing new methods into the proxy class as the program needs them:
The body of the previous AUTOLOAD()
has become a closure (closures) bound over the name of the undefined method. Installing that closure in the appropriate symbol table allows all subsequent dispatch to that method to find the created closure (and avoid AUTOLOAD()
). This code finally invokes the method directly and returns the result.
Though this approach is cleaner and almost always more transparent than handling the behavior directly in AUTOLOAD()
, the code called by AUTOLOAD()
may detect that dispatch has gone through AUTOLOAD()
. In short, caller()
will reflect the double-dispatch of both techniques shown so far. While it may violate encapsulation to care that this occurs, leaking the details of how an object provides a method may also violate encapsulation.
Some code uses a tailcall (tailcalls) to replace the current invocation of AUTOLOAD()
with a call to the destination method:
This has the same effect as invoking $method
directly, except that AUTOLOAD()
will no longer appear in the list of calls available from caller()
, so it looks like the generated method was simply called directly.
AUTOLOAD()
can be useful tool, though it is difficult to use properly. The naïve approach to generating methods at runtime means that the can()
method will not report the right information about the capabilities of objects and classes. The easiest solution is to predeclare all functions you plan to AUTOLOAD()
with the subs
pragma:
That technique has the advantage of documenting your intent but the disadvantage that you have to maintain a static list of functions or methods. Overriding can()
(universal) sometimes works better:
AUTOLOAD()
is a big hammer; it can catch functions and methods you had no intention of autoloading, such as DESTROY()
, the destructor of objects. If you write a DESTROY()
method with no implementation, Perl will happily dispatch to it instead of AUTOLOAD()
:
If you mix functions and methods in a single namespace which inherits from another package which provides its own AUTOLOAD()
, you may see the strange error:
If this happens to you, simplify your code; you've called a function which does not exist in a package which inherits from a class which contains its own AUTOLOAD()
. The problem compounds in several ways: mixing functions and methods in a single namespace is often a design flaw, inheritance and AUTOLOAD()
get complex very quickly, and reasoning about code when you don't know what methods objects provide is difficult.
AUTOLOAD()
is useful for quick and dirty programming, but robust code avoids it.
Hey! The above document had some coding errors, which are explained below:
- Around line 3:
-
A non-empty Z<>
- Around line 201:
-
A non-empty Z<>