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

Hi again ,

I'm having loads'o trouble calling functions using code ref's from with an AUTOLOAD method - I have a package that should have a configurable way of handling exceptions - configuration being via the selection of a function from the standard functions e.g. die() or croak(), such that AUTOLOAD should cause a die() or croak() (or whatsoever) as appropriate. Assuming (in its simplest form), a package as follows ...

package fred; use Carp; our $DEFAULT_HANDLER = 'die'; . . or . our $DEFAULT_HANDLER = \¨ our $AUTOLOAD; sub AUTOLOAD { print STDERR "AUTOLOAD(@_) - $AUTOLOAD\n"; my $self = shift(); $DEFAULT_HANDLER-<('Died via indirection'); # a la Schwarz & Phoe +nix &$DEFAULT_HANDLER('Died via default'); }
and a call such as ...
fred->raise_exception("Some text");
If either or both the definition of $DEFAULT_HANDLER and the call to the referenced function are changed, the problem continues to manifest itself as follows ...
AUTOLOAD(fred Some text) - fred::raise_exception AUTOLOAD(Some text) - fred::die
The reference gets converted to the configured function call and then the search begins again for a method belonging to the package i.e. at no time does the configured function get called !! I'm using Strawberry perl on Win2K. Am I being spectacularly dense and missing something so obvious it's untrue, or is/may there be a problem ? Anybody any ideas ?? TIA ,
At last, a user level that best describes my experience :-))

Replies are listed 'Best First'.
Re: Problem using code ref's in AUTOLOAD
by bruceb3 (Pilgrim) on Aug 27, 2007 at 21:59 UTC
    The POD perlsub says that you can't a reference to a built in function using the syntax \&CORE::die.
    ...
    Even though it looks like a regular function call, it
    isn't: you can't take a reference to it, 
    such as the incorrect "\&CORE::open" might appear to produce.
    ...
    

    To get around this you could use an anonymous subroutine as the value to $DEFAULT_HANDLER.

    our $DEFAULT_HANDLER = sub { die @_ };

    Making this change seems to work.

    bruce:1:~/tmp $ cat p.pl #!/usr/bin/perl # vim: sw=4 use strict; use warnings; package fred; our $DEFAULT_HANDLER = sub { die @_ }; our $AUTOLOAD; sub AUTOLOAD { print STDERR "AUTOLOAD(@_) - $AUTOLOAD\n"; my $self = shift; $DEFAULT_HANDLER->('died via indirection'); } package main; my $fred = fred->raise_exception("some test"); bruce:1:~/tmp $ ./p.pl AUTOLOAD(fred some test) - fred::raise_exception died via indirection at ./p.pl line 9. bruce:1:~/tmp $
      Mmm, OK, looks like I'm being way dense ... you're right WRT code ref's, however, it doesn't explain why a call of the form
      package fred; our $DEFAULT_HANDLER = 'die'; sub AUTOLOAD { $&ref("Some text"); }
      doesn't work ... or my ignorance exceeds even my normal standards, and it does ?

        You are being very harsh on yourself. It looks like when a sub is referenced that doesn't exist autoload will only ever look in the current package. So when you are making subroutine call (as opposed to a method call) AUTOLOAD will only ever search for fred::die, which doesn't exist, hence the repeated calls to AUTOLOAD. Interesting.

        If the call to the missing subroutine is made as a method call, AUTOLOAD will search the current package and then the packages listed in the @ISA array. To get this to work the handler has to be called as a method, e.g.

        bruce:1:~/tmp $ cat p.pl #!/usr/bin/perl # vim: sw=4 #use strict; #use warnings; package bert; sub die { die @_; } package fred; our @ISA = qw( bert ); our $DEFAULT_HANDLER = "die"; our $AUTOLOAD; sub AUTOLOAD { print STDERR "AUTOLOAD(@_) - $AUTOLOAD\n"; my $self = shift; $self->$DEFAULT_HANDLER('died via indirection'); } package main; my $fred = fred->raise_exception("some test"); bruce:1:~/tmp $ ./p.pl AUTOLOAD(fred some test) - fred::raise_exception fred died via indirection at ./p.pl line 10. bruce:1:~/tmp $

        So how to make a package inherit from "CORE" ?