Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

call sub in string

by Anonymous Monk
on Feb 16, 2002 at 08:27 UTC ( [id://145825]=perlquestion: print w/replies, xml ) Need Help??

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

I would like to do something like

for (1..2) { "&function_$i" }

PerlCircus talked about using
@{[ ]}
in the string...but didn't explain what is happening...anyone care to enlighten me ;-)

Replies are listed 'Best First'.
Re: call sub in string
by Kanji (Parson) on Feb 16, 2002 at 09:01 UTC

    You're probably after an symbolic reference, and were almost but not quite there with your snippet...

    sub function_1 { print "One\n" } sub function_2 { print "Two\n" } { # Allow symbol table manipulation. # You do use strict;, right? :) no strict 'refs'; foreach my $no ( 1 .. 2 ) { &{ "function_$no" }; # <--- THIS THING } }

    ... but that could potentially blow up in your face if $no turned out to be something unexpected unless you wrapped the whole shebang inside an eval or made good use of can.

    The more preferable (and use strict;-happy) way of doing this sort of thing is using something called a dispatch table, which'd look something like ...

    sub function_1 { print "One\n" } sub function_2 { print "Two\n" } my %functions = ( 'DEFAULT' => sub { print "Huh?\n" }, 1 => \&function_1, 2 => \&function_2, ); foreach my $no ( 1 .. 3 ) { $no = 'DEFAULT' unless exists $functions{$no}; $functions{$no}->(); }

        --k.


      While in principle you are correct that dispatch tables are a good idea for this kind of thing, I would say that for this case or at least given how this case was posed dispatch tables would be overkill.

      The easier way to accomplish his goal without using symbolic refs and without using a disptach table is to simply loop over a list of subrefs.

      foreach my $sub (\&function_1,\&function_2) { $sub->(); }
      Of course Im somewhat curious why any good programmer would handroll numbered functions (i can see it with autogenerated subs, kinda), but I suspect our OP is a bit new to 'tings.

      :-)

      Yves / DeMerphq
      --
      When to use Prototypes?

Re: call sub in string
by Zaxo (Archbishop) on Feb 16, 2002 at 10:08 UTC

    First, I'll answer the question, then question the proposed code.

    Double quotes do not interpolste sub calls. The need, then, is to provide a context which does. The @ and $ sigils are interpolated in qq(), so "@{something}" and "${something}" are the choices. @{[foo]} needs an array ref inside, hence the square braces. "${\foo}" also works.(foo should already be defined)

    If you wish to make the call in scalar context, it is tempting to try "${\foo}" but that remains in list context. You need explicit scalar to get that.

    Now to your proposed code. You are using symbolic references when there is no need at all. Is the $i suffix you are trying to use supposed to be interpolated from the loop variable for my $i (1..2) {}? Why not make an honest array of sub refs? Viz:

    for (\&cut, \&paste, \&publish) { print LOG "@[[localtime]} did:", &$_,$/; }
    Second, why do you need to place the calls in quotes? If you need to produce stereotyped strings, @strings = map sprintf is to be preferred.

    Update; fixed typo in code, clarified function name scope issue.

    After Compline,
    Zaxo

Re: call sub in string
by kwoff (Friar) on Feb 16, 2002 at 08:50 UTC
    I've used this with heredocs in CGI scripts. Example:
    #!/usr/bin/perl sub top_html { return "<html><head>$_[0]</head><body>"; } print <<EOF; @{[top_html("catchy title")]} blah.. EOF

    Explanation:
    @{ somearef } takes an array reference "somearef" and dereferences it.
    [ somearray ] takes a list "somelist" and makes an array ref of it.
    @{ [ function() ] } takes the list returned by "function()" and wraps it in a way that is interpolatable by quotemarks.

      Sorry, you just hit a pet peeve of mine.

      I strongly recommend against using that interpolation trick. Just using interpolation takes one more character, is going to be a lot easier for people to pick up, and doesn't impose list context when scalar is more appropriate.

      If the last bit didn't make sense to you, try it with localtime. Fighting central ideas of the language just to be able to use cool tricks isn't a very good tradeoff.

      Now before you point out that heredocs don't allow you to break strings I should mention that they also wind up conflicting with my indentation. I therefore find that the qq() syntax works far better for me and is more flexible. (Unless, of course, your scripts are part of a bigger system and templating is a better idea than big fat heredocs.)

Re: call sub in string
by axelrose (Scribe) on Feb 17, 2002 at 22:15 UTC
    Perl6 will provide an easier way to achieve this by:
    "$(function_$i)"
    I would anyway suggest to code this better as:
    for ( 1..2 ) { function( $i ) }
    and process the different values in the function.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (8)
As of 2024-03-28 11:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found