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

I have a script which calls the following functions
   ⊤
   &middle;
   &end;
In a script to be required, I have the following definitions: (notice top is not defined)
   sub middle {}
   sub end {}
Is there a way to wrap the call to function top() with an if statement of some sort so it will not get a function undefined error?
Something like:
If top function exists {
   ⊤
}
  • Comment on Calling a function that may not be there...

Replies are listed 'Best First'.
Re: Calling a function that may not be there...
by Dominus (Parson) on Mar 27, 2001 at 11:11 UTC
    I suggest that you simply use:
    if (defined &top) { ⊤ }
    or
    &top if defined ⊤
    The defined operator returns true if &top is defined, false if there is no such function. This would appear to be exactly what you are looking for.

    You should avoid the solutions based on can for two reasons: First, they will be less efficient, and second they may have additional semantics that you don't want.

    The AUTOLOAD thing is utterly ridiculous. It's like squishing a bug with a pile driver.

      Edited becuase as Dominus pointed out, I was incorrect, and I wanted to disentangle my two points.

      If you simply wanted to call a bunch of subroutines in order you could be more clever:

      my @funcs = (); push @funcs, sub { print "middle\n"; }, sub { print "bottom\n"; }; push @funcs, some_subroutine_that_returns_sub_refs(); foreach my $sub (@funcs) { &$sub; }

      By passing the subroutine references around you can do lots of powerful things without depending on global subroutine names. It all depends on what you are really trying to do.

      -ben
        Said knobunc:
        That would work if there was a reference to the function involved. The original case had a simple subroutine definition.
        OK, you're wrong, and you obviously didn't try it, or even look in the manual.

        Says perlfunc:defined:

        You may also use defined(&func) to check whether subroutine &func has ever been defined.
        With all that code you wrote to show off, I would have thought you could also write the following three-line test to avoid embarassing yourself:
        sub a1 {} print "a1 is defined\n" if defined &a1; print "a2 is defined\n" if defined &a2;
Re: Calling a function that may not be there...
by Benedictine Monk (Novice) on Mar 27, 2001 at 04:17 UTC
    By far the easiest way to do this is to use can():
    #Require the file with the function definitions. #Use eval to catch errors. eval { require "definitions.pl"; }; #__PACKAGE__ is a token that gets replaced with the #name of the current package. You must not quote it. #Why? Because Perl said so. my $package = __PACKAGE__; #Add a 'can' test to each function call... #This is the shortest. It uses object-oriented #calling syntax: top() if $package->can('top'); #If you don't like dangling if's, try this: if ($package->can('middle')) { middle(); } #This short-cuts the object-oriented calling syntax, #and uses the relatively obscure UNIVERSAL package #directly. #IMO it's really messy, but it's technically the fastest. end() if UNIVERSAL::can($package,'end');

    Hope this helps!

    Jerry

    Edit: chipmunk 2001-03-29

      You don't need a temporary variable. Just use __PACKAGE__->can('subname')
Re: Calling a function that may not be there...
by japhy (Canon) on Mar 27, 2001 at 04:09 UTC
    You could use the AUTOLOAD approach, or, if you know ahead of time which functions might cause trouble, you can use an eval BLOCK approach:
    # I know foo() and bar() exist... # but not too sure of xyzzy() or quux() foo(); eval { xyzzy() }; # $@ will have a value if xyzzy() isn't defined bar(); eval { quux() }; # $@ will have a value if quux() isn't defined


    japhy -- Perl and Regex Hacker
(crazyinsomniac) Re: Calling a function that may not be there...
by crazyinsomniac (Prior) on Mar 27, 2001 at 03:18 UTC
    Look into %::, or %main::.

    It's an anon hash that every script/package has and it contains a lot of stuff, including all functions that aren't stored like my $subo = sub {return "i am private"; };

    Print it, see what develops $%^).

     
    ___crazyinsomniac_______________________________________
    Disclaimer: Don't blame. It came from inside the void

    perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

Re: Calling a function that may not be there...
by markwild (Sexton) on Mar 27, 2001 at 03:35 UTC
    I think what you are looking for is the AUTOLOAD routine. Take a look at page 296 of the Camel Book v3. The section called 'Autoloading' starts by saying "Normally, you can't call a subroutine that isn't defined. However, if there is a subroutine named AUTOLOAD in the undefined subroutine's package, then the AUTOLOAD subroutine is called with the same arguments that would have been passed to the original subroutine. . . ." Hope that puts you in the right direction.