Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Yet another does-function-exist question

by xaprb (Scribe)
on Apr 14, 2007 at 15:15 UTC ( [id://610069]=perlquestion: print w/replies, xml ) Need Help??

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

There are several threads on "how can I find if this function exists." Mine is about Perl built-ins and functions possibly imported from another module. I want to be able to take any string and decide, without calling it as a function, whether it can be called as a function.

defined() and exists() aren't giving me the love I've needed since I was a child:

use List::Util qw(min); sub foo {} print defined(&foo); # prints 1 print defined(&time); # prints '' print defined(&min); # prints ''

Edit: I made a mistake with min, defined(&min) does work. But defined(&time) still does not.

exists() gives similar results.

Any suggestions? Thanks in advance!

Replies are listed 'Best First'.
Re: Yet another does-function-exist question (eval sub)
by tye (Sage) on Apr 14, 2007 at 16:22 UTC
    sub definedWord { my( $word )= @_; return eval "use strict; my \$x= sub { $word }; 1" || ( warn("$@\n"), $@ !~ /^Bareword/ ); } @ARGV= qw( definedWord time system foo BEGIN if -e lt goto last ) if ! @ARGV; for( @ARGV ) { printf "$_:\t%sdefined\n", definedWord($_) ? "" : "UN"; }

    is one interesting interpretation, producing:

    definedWord: defined time: defined system: defined Bareword "foo" not allowed while "strict subs" in use at (eval 4) line + 1. foo: UNdefined BEGIN: defined syntax error at (eval 6) line 1, at EOF if: defined -e: defined syntax error at (eval 8) line 1, near "{ lt" lt: defined goto: defined last: defined

    - tye        

      Neat! It seems to consider a lot of things to be defined that aren't so executable. All of these, for instance:

      @ARGV= qw( ; "foo" 123 {} [] ) if ! @ARGV; # etc. __END__ ;: defined "foo": defined 123: defined {}: defined []: defined

        As the name implies, it is meant to be passed a word. (Since non-words can't be called as subroutines without unusual syntax.)

        - tye        

        If that really matters for an example, definedWord could be just powered with regex. ++tye.

        Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

      I like this idea a lot. Thanks for the suggestion.

Re: Yet another does-function-exist question
by Joost (Canon) on Apr 14, 2007 at 15:56 UTC
Re: Yet another does-function-exist question
by kyle (Abbot) on Apr 14, 2007 at 16:29 UTC

    This also does not work with built-ins:

    use List::Util qw(min); sub foo {} $x = time(); foreach my $thing ( qw( x foo min time ) ) { printf "$thing is code: %s\n", ( ref *{$main::{$thing}}{CODE} ) ? 'Yes' : 'No'; } __END__ x is code: No foo is code: Yes min is code: Yes time is code: No

    Perhaps you could tell us what problem you're really trying to solve?

    If you have some string, and you want to know if it could do something under eval without actually executing it, perhaps you could use 'perl -c' for that. Or, to be really ugly, shell out and see what 'perldoc -f' has to say about it (being very careful about quoting the argument, of course). That would detect built-ins, and you could use one of the other methods listed here for detecting everything else.

      I'm trying to examine a string of input and decide which words m/\b(\w+)\b/g are executable, without executing them. If executable I leave them alone; if not I do something off-topic with them.

Re: Yet another does-function-exist question
by f00li5h (Chaplain) on Apr 14, 2007 at 15:32 UTC

    Just call it and see what happens.

    sub bar { print 'woot' } for my $thing (qw/ foo bar /){ print "$thing :$/"; eval{ no strict refs; &{$thing}(@_); # possibly a nasty symbolic reference }; warn "You can not call $thing: $@ " if $@; }

    gives you something like:

    The main point being, that you can just catch the die from eval and move on.

    Why ask if something looks like it will fail, when you can just suck it and see?

    if you're involving objects, UNIVERSAL's can may also interest you

    @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;

      I'm trying to do the opposite of what you're suggesting. I explicitly don't want to call it if it's a function.

      $func = "format_hard_drive"; print "Good news, function exists!" if eval { &$func() };

        You can do it one of two ways.

        1. Check that the thing is valid before hand (as ref $coderef in my class below does)
        2. Check when you call that the result is valid (as the trigger_event sub will do if you remove the test in the first point)

        At the risk of getting a TL;DR, here's something that takes coderefs and then dispatches events with them, as I wrote this, I realised that it's surprisingly long for a simple example ;)

        This is the class that takes care of dispatching the events (to a single handler for each event type)

        This is the client code, that registeres event handlers (to be used as callbacks) and triggers the actual events on the object. Normally, the object would find it's own events, and handle them within a run() type method (Tl's MainLoop for example)

        The class will reject 'antelope' because it's not a real coderef, although if you were to pass in 'main::antelope' as the name, and remove the check for ref $coderef, you should be able to use just names of subs. I don't see why you would want to do this, since it's the same number of characters to write \& as it is to enclose the sub's name quote likes

        Justification: this does answer your question about checking if it's callable before hand (because it uses ref $subref to decide if it can be callled (long before the events actually turn up). This is a fairly painless way to check if something is callable, you can also use anonymous subs if you want

        Hope this helps.

        @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2024-04-18 08:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found