Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Validating a Code Reference

by davorg (Chancellor)
on Aug 17, 2000 at 19:57 UTC ( [id://28310]=perlquestion: print w/replies, xml ) Need Help??

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

Given a reference to a subroutine, how would you go about checking the that referenced subroutine actually exists.

For example if I run

perl -e'print \&not_there'

I get back the reference CODE(0xeb570) which _looks_ like a valid subroutine reference, but (of course) isn't as the subroutine it claims to reference doesn't exist.

I suppose you can find out by running the reference in an 'eval' block, but you might not want to do that if the subroutine has potentially dangerous side effects.

--
<http://www.dave.org.uk>

European Perl Conference - Sept 22/24 2000, ICA, London
<http://www.yapc.org/Europe/>

Replies are listed 'Best First'.
Re: Validating a Code Reference
by chromatic (Archbishop) on Aug 17, 2000 at 20:11 UTC
    Use typeglobs. They're almost as good as caramel corn:
    #!/usr/bin/perl -w use strict; sub here { } foreach my $poss ( qw( here not_here ) ) { no strict 'refs'; if (*{$poss}{CODE}) { print "$poss exists.\n"; } else { print "$poss does not.\n"; } }
    What this does is look for a typeglob of a certain name. (That's the *{$poss} part.) Then it looks to see if the CODE slot is defined. I think you can take it from there.

    Update: I just read the 'reference' part. If it's an anonymous reference, that's trouble. (I think you'd have to get access to Perl guts to find it. Yikes.) If it's not, you can check the symbol table for a match. There's probably a better way to do this with grep, but this is illustrative:

    #!/usr/bin/perl -w use strict; sub findme { return 0; } sub another {} my $ref; if (rand(1) < 0.5) { $ref = \&findme; } else { $ref = \&another; } foreach (keys %main::) { no strict 'refs'; if (defined *{$_}{CODE}) { if (*{$_}{CODE} eq $ref) { print "\$ref points to $_!\n"; } } }
    It's not beautiful, and you'll have to have some idea which package the sub might be in, but it's a little closer.

      That was what I originally thought, but the problem is that I don't have the subroutine name, I only have a code ref. And as btrott points out, it might well be an anonymous code ref (which doesn't live in a typeglob).

      --
      <http://www.dave.org.uk>

      European Perl Conference - Sept 22/24 2000, ICA, London
      <http://www.yapc.org/Europe/>
      Very nice!

      OTOH I use anon subs a lot, and this approach will fail for those.

      Incidental note. After some testing it appears that if the sub exists when you define the sub reference, you get the first sub. Otherwise you get the first sub defined after that with that name. I tried various combinations of evals creating refs, defining subs, redefining subs, and that seemed to be what happened.

      Personally I would not worry about it. But I would like it if "strict 'subs'" disallowed making a reference to a sub that is not yet defined...

Re: Validating a Code Reference
by davorg (Chancellor) on Aug 17, 2000 at 22:58 UTC

    Thanks everyone for your help, but I think I've got a solution - and it's even simpler than I hoped for. Take a look at this:

    sub there { print "I'm here!"; } my %refs = (there => \&there, not => \&not_there, anon => sub { "I'm here too!" }); foreach (keys %refs) { print "'$_' is ", defined &{$refs{$_}} ? "valid\n" : "invalid\n"; }

    Which displays:

    'there' is valid 'not' is invalid 'anon' is valid

    Much kudos to Matt Freake of London.pm for coming up with the solution - defined &$coderef.

    --
    <http://www.dave.org.uk>

    European Perl Conference - Sept 22/24 2000, ICA, London
    <http://www.yapc.org/Europe/>
Re: Validating a Code Reference
by btrott (Parson) on Aug 17, 2000 at 20:11 UTC
    This is a very interesting question, and I'd love to see an answers/solution from someone. I can't really provide an answer myself, but after thinking about it a bit, I'm not sure that this is going to be possible.

    Think of anonymous subs, for example:

    printf "%s\n", sub { "foo" };
    That prints out
    CODE(0x45f73b0)
    The tricky thing that I'm pointing out here is that you certainly couldn't "look up" an anonymous sub to ensure that it exists; but the code reference looks just like a reference to a named subroutine, and if you do
    my $type = ref $sub;
    you'll get "CODE" either way. In other words, a reference to an anonymous sub looks just like a reference to a named sub; and if you can't look up one then you may not be able to look up the other. :)

    The only "solution" really may be to try and run the sub. I guess the problem here is that the only way of dereferencing a code reference is to *run* it; and that's what you want to avoid. But if that's the only way, then... anyway.

    I hope to see some more encouraging answers, though.

Re: Validating a Code Reference
by tye (Sage) on Aug 17, 2000 at 20:27 UTC

    I notice that the debugger's "x" command seems to know how to do this so I dug a bit and found Devel::Peek::CvGV(), which will fail if your ref is to a sub that doesn't exist.

            - tye (but my friends call me "Tye")
Re: Validating a Code Reference
by athomason (Curate) on Aug 17, 2000 at 20:17 UTC
    Update:Read the end to see why this is offtopic and not relevant to the question, but in any case don't vote it up! But read on anyway for info about an interesting behavior...

    Welcome to autovivification. By creating the ref you implicitly tell perl to assume it exists, and so the reference is created, despite the non-existence of the sub. From perldoc perlref:

    6. References of the appropriate type can spring into existence if yo +u dereference them in a context that assumes they exist. Because we haven't talked about dereferencing yet, we can't show you any examples yet.
    Skip a few...
    3. Subroutine calls and lookups of individual array elements arise often enough that it gets cumbersome to use method 2. As a form of syntactic sugar, the examples for method 2 may be written: $arrayref->[0] = "January"; # Array element $hashref->{"KEY"} = "VALUE"; # Hash element $coderef->(1,2,3); # Subroutine call The left side of the arrow can be any expression returning a reference, including a previous dereference. Note that `$array[$x] +' is *not* the same thing as `$array->[$x]' here: $array[$x]->{"foo"}->[0] = "January"; This is one of the cases we mentioned earlier in which references could spring into existence when in an lvalue context. Before this statement, `$array[$x]' may have been undefined. If so, it's automatically defined with a hash reference so that we can look up `{"foo"}' in it. Likewise `$array[$x]->{"foo"}' will automatically get defined with an array reference so that we can look up `[0]' i +n it. This process is called *autovivification*.
    The same thing has happened to you, but with a sub instead of an array. Just be careful you don't create references to things which don't exist. See chromatic's answer for how to do that with a real sub. If it's an anonymous sub, you probably should never have created the false reference to begin with ;-).

    UPDATE: Never mind: merlyn pointed out that autovivification yields a structure with stuff in it, unlike this (the coderef exists, but it's useless). But it's still good to know :-).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://28310]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2024-04-23 21:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found