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

I saw somewhere online, someone used code to check if subroutine existed, before calling it.

I have to do something on a live site, so I cannot test it first, so wondering if you can tell me if this would work:

my $_tsub = "SendMultiPartMemberEmailMimeLiteSendGrid"; if(exists &{$_tsub}) { # send code to call it... } else { require "/path/to/the/file/SendMultiPartMemberEmailMimeLiteSen +dGrid.pl"; # send code to call it now that we pulled it in... }
I an just wondering if that would actually work? or is that not how to check it?

Thanks for any advice on it.

Replies are listed 'Best First'.
Re: Checking on live site if subroutine exists
by LanX (Saint) on Mar 27, 2021 at 01:46 UTC
    > I an just wondering if that would actually work?

    It's documented that way, see exists

    exists ⊂    # OK

    and symbolic code-refs are not limited by strict

    DB<281> use strict; use warnings; $a=""; print exists &{$a} DB<282> sub foo {}; $a="foo" DB<283> use strict; use warnings; print exists &{$a} 1 DB<284>

    Tho I prefer PACKAGE->can('subname') b/c it's more readable and returns a coderef.

    See UNIVERSAL for documentation.

    edit

    OK there is indeed a fine difference here, because ->can would also report inherited methods and exists wouldn't.

    Point is, if you are using OOP, then can is what you normally want.

    Otherwise without OOP, you can't get bitten by inheritance.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: Checking on live site if subroutine exists
by tobyink (Canon) on Mar 30, 2021 at 11:01 UTC

    Just a minor comment about this pattern:

    my $_tsub = "SendMultiPartMemberEmailMimeLiteSendGrid"; if(exists &{$_tsub}) { # code to call it } else { require "/path/to/the/file/SendMultiPartMemberEmailMimeLiteSen +dGrid.pl"; # code to call it }

    Your code to call it is unnecessarily duplicated. Better:

    my $_tsub = "SendMultiPartMemberEmailMimeLiteSendGrid"; if ( not exists &{$_tsub} ) { require "/path/to/the/file/SendMultiPartMemberEmailMimeLiteSen +dGrid.pl"; } # code to call it

    But this can probably be even better written as:

    require "/path/to/the/file/SendMultiPartMemberEmailMimeLiteSendGri +d.pl"; # code to call it

    Because require is smart enough to not load the same file twice.

Re: Checking on live site if subroutine exists
by haukex (Archbishop) on Mar 27, 2021 at 07:39 UTC

    You've already gotten some good answers, I just wanted to point out:

    I have to do something on a live site, so I cannot test it first, so wondering if you can tell me if this would work

    The most common solution to this nowadays is to set up a test environment that mirrors the production environment. Of course it's a bit of work, but one has to weigh this against the risk of bringing down the production system because one is using it to test things. In any case, you could answer your question yourself by setting up a SSCCE independently of a test system. However:

    I saw somewhere online, someone used code to check if subroutine existed, before calling it.

    I think this is a bit of a strange requirement, could you explain a bit more? Why not just do require "/path/to/the/file/SendMultiPartMemberEmailMimeLiteSendGrid.pl"; and be done with it? Or do you have multiple versions of the sub coming from different include files, or something like that?

Re: Checking on live site if subroutine exists
by ikegami (Patriarch) on Mar 27, 2021 at 05:54 UTC
    require won't do anything if you've already loaded the file, so all you need is
    require("/path/to/the/file/SendMultiPartMemberEmailMimeLiteSendGrid.pl +");

    Seeking work! You can reach me at ikegami@adaelis.com

Re: Checking on live site if subroutine exists
by perlfan (Parson) on Mar 27, 2021 at 02:24 UTC
    You could also execute it in the context of an eval block; then have a reasonable default if it fails; even if it is to do nothing:
    local $@; my $ok = eval { require q{/path/to/script.pl}; # send code to call it now that we pulled it in... 1; };
    You might want to check $ok or $@. NB: I don't always test in production, but when I do; I use the block form of eval.
      This subroutine sends an email to a member for one they asked for, like a notice when someone they referred joins, etc.

      So, does calling it with an eval or checking if it exists actually execute it?

        > So, does calling it with an eval

        yes

        > or checking if it exists actually execute it?

        no

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        To add to what LanX said, eval effectively hides any errors that might occur when executing what's in the block.

        Since this is a .pl file and require happens at runtime, you may get away with just checking if this file contains some expected characteristics before calling require - like actually existing (or containing some expected text). That said, it's better practice to create an actual Perl module and esure it can be found via @INC (i.e., via PERLLIB, PERL5LIB, or judicious use of FindBin + use lib ....
Re: Checking on live site if subroutine exists ( Module::Loaded Module::Load )
by Anonymous Monk on Mar 27, 2021 at 02:42 UTC