Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

subroutine refs

by CColin (Scribe)
on Nov 30, 2007 at 10:37 UTC ( #654080=perlquestion: print w/replies, xml ) Need Help??
CColin has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I have a program which takes an input file that includes a string which tells the program which subroutine to use (from an imported file of subroutines, using the "do" statement) at a certain point. (The input file changes through the day, so different subs are needed at different points). I save the imported string as
my $generic_sub ="name of sub to use"
Then, at the point in the program when I want to use the sub, call
$return value = &$generic_sub(arguments)
Problem: using strict this throws the error:
Can't use string ("name of sub") as a subroutine ref while "strict ref +s" in use at program_name_1.0 line 153.
I've read the perlref docs about using references to name subroutines, but that doesn't seem to solve the problem, in that I still need to use the name of the string from the input file to determine which subroutine to use, whether that subroutine is referred to by a reference or not. And it is the use of the string as a subroutine ref that is causing the error, right? Thanks for any pointers. Colin

Replies are listed 'Best First'.
Re: subroutine refs
by wfsp (Abbot) on Nov 30, 2007 at 10:47 UTC
    Perhaps consider a dispatch table. It would break the direct link between data coming from outside and your code.

    Have a look at Implementing Dispatch Tables in the tutorials section.

Re: subroutine refs
by moritz (Cardinal) on Nov 30, 2007 at 10:42 UTC
    One solution:

    { # start a new scope to keep the effect of "no strict" small no strict 'refs'; $return_value = &$generic_sub(@args); }

    Another involves eval:

    $return_value = eval("$generic_sub(\@args)"); die $@ if $@;
Re: subroutine refs
by fenLisesi (Priest) on Nov 30, 2007 at 13:15 UTC
    It is likely that the application can (and perhaps should) be rearchitected, but let's not go there. In addition to the suggestions above, one quirky way would be to use OO syntax, but that would add an argument to all your sub definitions. For example:
    use strict; use warnings; my $meth_name = 'foo'; __PACKAGE__->$meth_name('camel'); exit( 0 ); sub foo { my ($self, $arg) = @_; print "$arg (on behalf of $self)\n"; }

    which prints

    camel (on behalf of main)
Re: subroutine refs
by sundialsvc4 (Abbot) on Nov 30, 2007 at 16:33 UTC

    I definitely prefer the “dispatch table” idea, because this gives you the very-important ability to know what the actual possibilities are. And, most importantly, to do something intelligent if what you've actually read from your input file is, for whatever reason, “none of the above.” (Hey, 'ka-ka occurs!' and your programs must be ready for that.)

    The idea here, as stated elsewhere, is that you create a hash containing all the possible key-values and a reference to the subroutine that is to handle each one. (Be sure to check for 'undef' ... which will occur if the input-value isn't in the table.) This trivializes the inevitable case where two-or-more inputs need to be handled by the same routine. Perhaps the greatest benefit of all is that it very-clearly documents what inputs this program will accept and what it will do with each one.

Re: subroutine refs
by broquaint (Abbot) on Nov 30, 2007 at 18:19 UTC
    You can safely create a reference to a subroutine by name and the execute that e.g
    use strict; sub dynamic { print "Mmm, dynamic.\n"; } my $name = 'dynamic'; my $subref = \&$name; &$subref();


      I find this very surprising. But I checked it and it apparently works.

      Why does this give an error:

      use strict; sub dynamic { print "hello\n"; } my $name = "dynamic"; &$name();
      .. and yet this is ok? (they differ only in the last line)
      use strict; sub dynamic { print "hello\n"; } my $name = "dynamic"; &{ \&$name }();
      Before seeing this, I would have bet anything that the &{\&{ ... }} operation was absolutely the same as &{...} (barring weird action-at-a-distance caused by tying, overloading, etc). In fact, I'm not sure whether to consider this a bug or not. Indeed, what is \&$name doing other than "using string as a subroutine ref", which is outlawed under strict refs?

      Yet a similar idea with other kinds of refs doesn't do this. Both of these examples fail under strict refs (in my mind because @{\@{...}} is unconditionally the same thing as @{...} ):

      use strict; our @dynamic = ("hello\n"); my $name = "dynamic"; print @$name;
      use strict; our @dynamic = ("hello\n"); my $name = "dynamic"; print @{ \@$name };
      My conclusion is that there is an important distinction between naming a subroutine and invoking it, which is manifested bizarrely by different behaviors in the \&{blah} and &{blah} mechanisms.


      broquaint: This is amazing. I was looking for such a solution for a while.

      Thinking about it, is this canonical? (namely, documented)? or is it a quirk (an oversight in the Perl language design?)

        Removing the intermediate assignment to $name, broquaint’s code simplifies to:

        use strict; my $subref = \&{'dynamic'}; &$subref(); sub dynamic { print "Mmm, dynamic.\n"; }

        which is explicitly documented as an exception to the normal behaviour of strict 'refs' (see strict):

        There is one exception to this rule:

        $bar = \&{'foo'}; &$bar;

        is allowed so that goto &$AUTOLOAD would not break under stricture.

        So, yes, this is canonical.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: subroutine refs
by Anonymous Monk on Nov 30, 2007 at 16:17 UTC
    my $coderef=__PACKAGE__->can($subname) or die "$subname not found"; $coderef->(...);
Re: subroutine refs
by Anonymous Monk on Nov 30, 2007 at 21:15 UTC
    You're using a symbolic reference which can be Very Dangerous and produce Unexpected Results if the variable containing the subroutine name gets hold of a Reserved Word. Create a hash of references to subroutines. (or a hash of anonymous subroutines, since the names are superfluous at that point)
    my $subs = { "joes_routine" => \&joesub, "marks_routine" => \&marksub, ... }; $subchoice = GetSubToUse(); @args = GetSubArgs(); $subs->{$subchoice}->(@args);
      In case if the variable can contain a reserved word, one could check the variable against a list of all reserved words, before calling it.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://654080]
Approved by moritz
Front-paged by grinder
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (5)
As of 2018-03-23 03:20 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (287 votes). Check out past polls.