Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I use Perl's AUTOLOAD?

In "Perl Best Practices" the very first line in the section on AUTOLOAD is:

Don't use AUTOLOAD

However all the cases he describes are dealing with OO or Modules.

I have a stand alone script in which some command line switches control which versions of particular functions get defined. Now I know I could just take the conditionals and the evals and stick them naked at the top of my file before everything else, but I find it convenient and cleaner to put them in AUTOLOAD at the end of the file.

Is this bad practice / style? If you think so why, and is there a another way to do it?

As per brian's request

I'm basically using this to do conditional compilation based on command line switches.

I don't mind some constructive criticism.

sub AUTOLOAD {
    our $AUTOLOAD;

    (my $method = $AUTOLOAD) =~ s/.*:://s; # remove package name
    if ($method eq 'tcpdump' && $tcpdump) {
        eval q(
        sub tcpdump {
            my $msg = shift;
            warn gf_time()." Thread ".threads->tid().": $msg\n";
        }
        );
    } elsif ($method eq 'loginfo' && $debug) {
        eval q(
        sub loginfo {
            my $msg = shift;
            $msg =~ s/$CRLF/\n/g;
            print gf_time()." Thread ".threads->tid().": $msg\n";
        }
        );
    } elsif ($method eq 'build_get') {
        if ($pipelining) {
            eval q(
            sub build_get {
                my $url = shift;
                my $base = shift;
                $url = "http://".$url unless $url =~ /^http/;
                return "GET $url HTTP/1.1${CRLF}Host: $base$CRLF$CRLF";
            }    
            );
        } else {
            eval q( 
            sub build_get {
                my $url = shift;
                my $base = shift;
                $url = "http://".$url unless $url =~ /^http/;
                return "GET $url HTTP/1.1${CRLF}Host: $base${CRLF}Connection: close$CRLF$CRLF";
            }    
            );
        }    
    } elsif ($method eq 'grow') {
        eval q{ require Convert::Scalar qw(grow); };
        if ($@) {
            eval q( sub grow {} );
        }
        goto &$method;
    } else {
        eval "sub $method {}";
        return;
    }
    die $@ if $@;
    goto &$method;
}
like image 742
Robert S. Barnes Avatar asked Mar 17 '10 08:03

Robert S. Barnes


People also ask

What is the difference between autoloader and autosplit?

The AutoSplit and AutoLoader modules automate the creation of forward declarations. The AutoSplit module creates an 'index' file containing forward declarations of all the AutoSplit subroutines. When the AutoLoader module is 'use'd it loads these declarations into its callers package.

How do I use autoloader's auto-load_sub function?

Starting with AutoLoader 5.73, you can call the AutoLoader::autoload_sub function with the fully-qualified name of the function to load from its .al file. The behaviour is exactly the same as if you called the function, triggering the regular AUTOLOAD mechanism, but it does not actually execute the autoloaded function.

Is there an autoloader with no external files?

SelfLoader - an autoloader that doesn't use external files. AutoLoader is maintained by the perl5-porters. Please direct any questions to the canonical mailing list. Anything that is applicable to the CPAN release can be sent to its maintainer, though. Author and Maintainer: The Perl5-Porters <[email protected]>

What is the difference between @incautoloader and selfloader?

AutoLoader may fail to find the autosplit files (or even find the wrong ones) in cases where @INC contains relative paths, and the program does chdir. SelfLoader - an autoloader that doesn't use external files.


1 Answers

If your only reason for using AUTOLOAD is to relocate the block to the end, why not put it at the end in a subroutine, and then call it as soon as its dependent variables are defined?

sub tcpdump;  # declare your subs if you want to call without parens

# define the parameters

compile();

# code that uses new subs

sub compile {
    *tcpdump = $tcpdump ? sub {
        my $msg = shift;
        warn gf_time()." Thread ".threads->tid().": $msg\n";
    } : sub {};
    # ...
}
# EOF

Better still, if the globals aren't needed elsewhere, just pass the values to compile as arguments.

like image 124
Eric Strom Avatar answered Sep 30 '22 23:09

Eric Strom