http://www.perlmonks.org?node_id=513944

water has asked for the wisdom of the Perl Monks concerning the following question:

I am using a third-party module that uses AUTOLOAD to allow you to call options in a "convenient" way.

The autoload isn't needed -- you can set the options with an explicit $obj->options() method, but the author I guess thought it'd be nice to allow $obj->some_random_option() calls and used AUTOLOAD for this.

Yuck.

And the author's AUTOLOAD doesn't check anything, it just dispatches everything to  $obj->option(some_random_option=>blah blah), without checking if  some_random_option is supported.

I'm encountering some errors in the module, which I don't fully understand yet, which lead to the objects unexpected demise, which leads to a DESTROY call, which AUTOLOAD happily dispatches to options.

Yuck again.

Is there a way for me, while debugging, to mangle the symbol table to remove Foo::Bar::Baz::AUTOLOAD subroutine?

I do not / can not modify Foo/Bar/Baz.pm.

Thanks!

water

PS I think I recall in Damian's PBP Dog book, he states AUTOLOADs are bad, and I agree! Too much magick.

Replies are listed 'Best First'.
Re: removing someone elses AUTOLOAD
by xdg (Monsignor) on Dec 04, 2005 at 13:48 UTC
    Is there a way for me, while debugging, to mangle the symbol table to remove Foo::Bar::Baz::AUTOLOAD subroutine?

    You should be able to redefine the subroutine by assigning a code reference to the appropriate glob.

    *Foo::Bar::Baz::AUTOLOAD = sub { 1 };

    I'd assume that you can make that happen in the debugger by typing it in as an expression. For example, see this debugger session I just tried:

    (0) $ perl -de 1 Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): 1 DB<1> *main::AUTOLOAD = sub { print "$main::AUTOLOAD @_" } DB<2> main->foo(1,2,3) main::foo main 1 2 3 DB<3>

    You could probably even save the original AUTOLOAD code reference to a new, lexical variable, and use it to call the original AUTOLOAD in your replacement after filtering out calls to DESTROY -- that would hopefully keep the rest of the code working, too, if that was important.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: removing someone elses AUTOLOAD
by Tanktalus (Canon) on Dec 04, 2005 at 15:26 UTC

    Theoretically, if you called $obj->option('some_random_option'), option needs to handle it anyway. So I don't see much of a problem with that tactic. It means there is only a single point at which one needs to validate the option is valid.

    It sounds like option isn't validating what is passed in - that's a seperate issue, and has absolutely nothing to do with AUTOLOAD.

    What does have something to do with AUTOLOAD is the fact that it's not dealing with DESTROY. The simplest way to deal with that is to create a DESTROY method:

    { package Foo::Bar; sub DESTROY {} }
    Once you've done this, DESTROYs won't be dispatched to AUTOLOAD at all.

    I don't think AUTOLOADs are necessarily bad, but I do see that they give a lot of temptation to develop badly. Right up there with eval STRING and goto. (That AUTOLOAD is often paired with goto is another issue.) Used appropriately, you can really take advantage of the dynamic nature of perl and provide syntactic sugar that you just can't do in any many other languages.