Search code examples
perlmoosesymbol-tablemop

Explain this witchcraft!!! (in Perl, with Moose and namespace::autoclean)


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.


Solution

  • 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.