It's actually quite simple. For
some_sub()
some_sub
is resolved at compile time. For
$o->some_method()
some_method
is resolved at runtime. It cannot be done at compile-time since it depends on the value of $o
.
Pergunta
So these days I'm working with a project that uses Perl and Moose. I understand Moose is built on MOP. I'm not too familiar with MOP, and I've encountered something I don't understand, and I could use a theoretical explanation. Here is the module namespace::autoclean
's documentation:
SYNOPSIS
package Foo;
use namespace::autoclean;
use Some::Package qw/imported_function/;
sub bar { imported_function('stuff') }
# later on:
Foo->bar; # works
Foo->imported_function; # will fail. imported_function got cleaned after compilation
So, back before I ever used Moose, the way that you called a method on an object was: the Perl interpreter would look up that method in the symbol table of the package that your object was blessed into (then, if not found, consider @ISA
inheritance and the like). The way it called an imported function from within the package was: it looked up the name of the function in the symbol table of the package. As far as I've been aware to date, that means the same symbol table, either way, so this behavior should be impossible.
My initial inspection of the source was not productive. In broad terms, what is different when using Moose, MOP, and namespace::autoclean, that this sort of trickery becomes possible?
ed. To be especially clear, if I were to replace use namespace::autoclean
with
CHECK { undef *Foo::imported_function }
then the Foo->bar;
call described in the documentation would crash, because Foo->bar
doesn't know where to find imported_function
.
Solução
It's actually quite simple. For
some_sub()
some_sub
is resolved at compile time. For
$o->some_method()
some_method
is resolved at runtime. It cannot be done at compile-time since it depends on the value of $o
.
Outras dicas
There is nothing here that is non-standard. The line
use Some::Package qw/imported_function/;
imports imported_function
into the current package, so Foo::imported_function
is the same subroutine as Some::Package::imported_function
. That assumes that Some::Package
inherits from Exporter
to do the necessary manipulation of the symbol tables.
The calls are method calls, so Foo->bar
is the same as Foo::bar('Foo')
. The only special thing here is that the magic that has been done by the import
function from Exporter
is undone at the end of compile time by namespace::autoclean
.
I haven't looked at the code for this module, but since a package's symbol table is just a hash (known as a stash, for symbol table hash) it would be easy to preserve its state at one point and restore it afterwards. So I would guess namespace::autoclean
takes a snapshot of the symbol table when it is loaded and the restores that state at the end of compilation time. This can conveniently be done in a CHECK
block which behaves like a BEGIN
block but is executed at the end of compilation and before the run starts.