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

Hello Monks,

I'm looking for a way to verify if a subroutine reference is valid. For example (when run with use strict, of course), my $sub = \&non_existent_sub; compiles fine, even if non_existent_sub was never declared. Worse still, $sub actually contains a CODE reference (to what? I'm not sure). It's only when I try to execute the sub (&$sub()) that perl fails, complaining of an undefined subroutine.

Is there any way to analyze $sub to determine that it points to an invalid subroutine? Apart from trying to execute it, of course. I've read Can I Force perl to Check Subroutine References at Compile Time?, but it didn't really answer my question, or if it did, then I missed it.

The reason I ask is that I'm trying to re-invent the user-supplied-code-execution wheel. I'm playing with an idea that's best captured in the following snippet:

#!/usr/bin/perl -w use strict; require $ARGV[0]; my $sub = eval "\\&$ARGV[1]"; &$sub;
The script's first argument is a file containing perl subroutine declarations, and the second argument is the name of the subroutine to call. My hope (correct me if I'm wrong) is that the require will catch user code errors early on, and resolving it to an actual subroutine reference simplifies calling the user code.

Of course, my real application is much more convoluted. The supplied functions are used as callbacks in the program, so the callback link has to be declared early in the program (this is when I want to check user input) even if the function might only get called much much later, potentially not even in the same execution run.

Of course, I'm also open to criticism if this is all a horrible idea.

Replies are listed 'Best First'.
Re: How do I test the validity of a CODE reference?
by Corion (Patriarch) on Aug 07, 2008 at 21:03 UTC

    You don't need eval and you can just inspect the main namespace for whether a subroutine of that name is defined:

    use strict; use Data::Dumper; sub foo { print "foo\n"; } for my $subname (@ARGV) { my $glob = $::{$subname}; warn defined $glob ? "'*$subname' exists" : "'*$subname' not found"; if ($glob) { my $sub = *{$glob}{CODE}; warn defined $sub ? "'$subname' exists" : "'$subname' not found"; &$sub if $sub }; }
      couldn't you just do
      if ( my $sub = main->can($subname) ) { $sub->(...) }
      ?
        Not quite. can is meant for methods, so it obeys inheritance.
      The reason I decided to use eval is that the user can put the required code in a package, and I don't need to know anything about it as long as he uses the fully qualified name as the subroutine name.

      Out of curiosity, how would you examine the symbol table for a package whose name you get from a variable? I'm not very comfortable with the syntax for typeglobs and Perl symbol tables...

        You can inspect any package, as the symbols for My::Package live in the %My::Package:: hash. The easiest way to get at those hashes is via soft references:

        use strict; use Data::Dumper; my $package = 'Data::Dumper'; # just as an example { no strict 'refs'; # we're using strings as symbols. Nasty, but con +venient warn Dumper \%{ "$package\::" }; };
Re: How do I test the validity of a CODE reference?
by kyle (Abbot) on Aug 07, 2008 at 21:02 UTC

    If you're going to call the sub anyway, call it in an eval and see what happens. If some other error comes up, you can rethrow it with die.

    eval { &$sub }; if ( $@ =~ /^Undefined subroutine/ ) { # This is what happens when you call a bogus sub ref. } elsif ( $@ ) { die $@; }

      Probably $sub->() is a better idiom, for the same reason to prefer prefered() to &prefered -- no accidental arg passing.

Re: How do I test the validity of a CODE reference?
by dave_the_m (Monsignor) on Aug 07, 2008 at 21:11 UTC
    print "valid\n" if defined &$sub;

    Dave.

Re: How do I test the validity of a CODE reference?
by Perlbotics (Archbishop) on Aug 07, 2008 at 21:22 UTC
    Using '*foo{THING}'-notation (access to symbol table) seems to work:
    #!/usr/bin/perl use strict; sub foo { print defined $_[0] ? "It is me, $_[1]!\n" : "$_[1] does no live here.\n"; } my $sub = *nonfoo{CODE}; foo($sub, "nonfoo"); $sub = *foo{CODE}; foo($sub, "foo"); __END__ nonfoo does no live here. It is me, foo!
Re: How do I test the validity of a CODE reference?
by BrowserUk (Patriarch) on Aug 07, 2008 at 21:07 UTC

    You can't tell if a code ref actually has code behind it that way. \&anyNameHere will return an apparently valid code ref. The only way is to actually invoke it, so do the invocation within an eval block:

    print $_, ':', eval{ $_->(); 1 } ? "S'ok" : "Uht erd!" for sub{ print 'good code' }, \&doesNotExist;; good code CODE(0x194a9b4) : S'ok CODE(0x194a954) : Uht erd!

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: How do I test the validity of a CODE reference?
by syphilis (Archbishop) on Aug 08, 2008 at 01:56 UTC
    Seems you can also derive the answer by looking at the value of the CvOUTSIDE pointer attached to $sub. I think this will show up as the OUTSIDE value when you do a Devel::Peek::Dump($sub), but to access that value in a useful way from within a program you'll probably need XS/Inline::C:
    use warnings; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; SV * validate(CV * coderef) { if(CvOUTSIDE(coderef)) return newSVuv(1); return newSVuv(0); } EOC $cref1 = \&existent; $cref2 = \&non_existent; $foo = 'hello world'; print "\$cref1: ", validate($cref1), "\n"; print "\$cref2: ", validate($cref2), "\n"; print "\$foo: ", validate($foo), "\n"; # Fatal Error sub existent{}
    (I've not tested this approach beyond the extent provided by the above script.)

    Cheers,
    Rob
      defined (which already provides this functionality) and sub calls use CvROOT(sv) || CvXSUB(sv).

      Update: Only mentioned defined initially.

        defined (which already provides this functionality)...

        Yes, defined(&$sub) works fine, but the functionality seems different to me. My approach looks at the variable itself, whereas defined appears to be looking at the subroutine referenced by the variable.

        Anyway .... my point is very moot .... at best :-)

        Cheers,
        Rob
Re: How do I test the validity of a CODE reference?
by FunkyMonk (Bishop) on Aug 07, 2008 at 21:17 UTC
    What about using can...
    eval do { local $/; <DATA> }; # psuedo require! die $@ if $@; for my $sub ( 'foo', 'undefined' ) { if ( main->can($sub) ) { main->$sub; } else { print "$sub() not defined\n"; } } __DATA__ sub foo { print "foo() worked\n"; }


    Unless I state otherwise, all my code runs with strict and warnings
Re: How do I test the validity of a CODE reference?
by gone2015 (Deacon) on Aug 11, 2008 at 17:24 UTC

    I've got a little module/pragma that will spot this kind of problem at compile-time: see "pragma" ensure...

    ...I'm interested in whether people find it useful. So any and all comments gratefully received.