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

Hi,
I have a subroutine that returns some stored config data when a config element is passed to it. (i.e. config('username') would return the username I have stored.) I'm using use configModule qw(config) in many of my scripts so I can simply and easily call config('something') throughout my script and get the values I need.

However, here is an example of the problem I'm running in to:
print "config('username') is my username";
This returns "config('username') is my username" instead of "rlang is my username." I've tried calling it like this: &config() and this: \&config, but no cigar.

I know I could do something along these lines:
my $username = config('username');
...but that would eliminate almost all the convenience and flexibility I'm going for. I've never tried calling a subroutine in the way I'm trying to do...is it even possible?

Eventually I'm trying to use the results of my config subroutine to pass to yet another subroutine. That seems like a different question for a different time, but maybe solving the above problem will lead to a solution for this too.

Any ideas for me? Thanks!

Replies are listed 'Best First'.
Re: Using Subroutine Returns
by almut (Canon) on Apr 23, 2009 at 00:17 UTC

    So, you're trying to interpolate the return value of a subroutine into a string? That would be:

    print "@{[config('username')]} is my username";

    (i.e., you fill an anonymous array with one value, and then dereference it with @{} — which works because arrays are interpolated)

    Similarly, you could also do (using a scalar ref)

    print "${\config('username')} is my username";

      This is not a general solution for interpolating subroutines. Whether you use "${\foo()}" or "@{[foo()]}", foo() will be running in list context. In contrast, foo() . '...' and "$username" both run in scalar context.

      If the return value is context sensitive, the list context value will be returned instead of the expected scalar context value, as this code snippet demonstrates:

      sub foo { wantarray() ? 10 : 1; } print 'Scalar context: '; print ''. foo(); print ', '; print foo() . "\n"; print 'List context: '; print "@{[foo()]}, "; print "${\foo()}\n"; # outputs Scalar context: 1, 1 List context: 10, 10

      To preserve the scalar context without stuffing the return value into a variable, one must use concatentation, e.g. '' . foo() or  "mumble " . foo() . " the burrowgroves" (or forced scalar context as ig points out below).

      Best, beth

        Or force a scalar context on the interpolated subroutine calls:

        sub foo { wantarray() ? 10 : 1; } print 'Scalar context: '; print ''. foo(); print ', '; print foo() . "\n"; print 'List context: '; print "@{[foo()]}, "; print "${\foo()}\n"; print 'Scalar context: '; print "@{[scalar(foo())]}, "; print "${\scalar(foo())}\n"; __END__ Produces: Scalar context: 1, 1 List context: 10, 10 Scalar context: 1, 1

        But, while this is possible, I can't imagine it being preferable to concatenation for producing a scalar context.

      So complicated and ugly! Just concatenate it with the '.' operator.
        So complicated and ugly!

        That's true, of course... but some people just want to interpolate :) — I have to admit I've also felt that urge at times...

        This is probably the outcome of the generalizing behavior of our brains: we've learnt we can interpolate scalars and arrays, so why not also hashes, functions, anything?  (This behavior, in and of itself, is certainly a Good Thing, BTW, otherwise we probably wouldn't be where we are today, messing with Perl... supported by those little silicon chips, etc.)

        Also, some people just find

        "abc ${\config('username')} xyz";

        easier to read/type than

        "abc ".config('username')." xyz";

        even though they are exactly the same number of chars.

        Anyhow, the nice thing is that with Perl's TIMTOWTDI-ness, everyone can get happy :)

        It is in a print, so a comma would be more natural than a dot. There is no need to build a single scalar when the operator takes a list.
        print config('username'), " is my username";
        Most likely the OP would want a \n in there too, but that isn't really part of the interpolation question.
      Thank you for your fast response! That's exactly what I needed.
Re: Using Subroutine Returns
by ikegami (Patriarch) on Apr 23, 2009 at 00:19 UTC

    Function calls aren't interpolated. You'll have to use fancy trickery (as already above) or directly use the concatenation that would result from the interpolation anyway

    print config('username') . " is my username";

    There's also printf

    printf "%s is my username", config('username');
Re: Using Subroutine Returns
by AnomalousMonk (Archbishop) on Apr 23, 2009 at 00:51 UTC
    As to your second question (or proto-question): passing the return value (or values) of one subroutine to another subroutine could be as simple as this:
    other_subroutine(config('username'), 'other', 'stuff');
    Much would depend on whether the  config() subroutine could return more than one item – but that's a discussion for another day.
Re: Using Subroutine Returns
by Marshall (Canon) on Apr 23, 2009 at 13:39 UTC
    print "config('username') is my username";

    This returns "config('username') is my username" instead of "rlang is my username."

    The reason that this doesn't work is that Perl doesn't know that config('username') is a subroutine!

    print config('username'), "is my username\n";
    should work fine. Perl print is a smart critter. There is no need for "." here. You just need comma separated things to print. Here are some examples..

    #!/usr/bin/perl -w use strict; print blah(); #Note: print blah instead of print blah() won't work! print "\n"; print lots_of_blah(); print "\n"; print blah(), " ", lots_of_blah(),"\n"; print lots_of_blah_with_newlines(); print blah(), " ", join(" ",lots_of_blah()),"\n"; sub blah { return "more blah"; } sub lots_of_blah { my @stuff = qw(a b c d); return @stuff; } sub lots_of_blah_with_newlines { my @stuff = ("a\n", "b\n", "c\n", "d\n"); return @stuff; } __END__ prints... more blah abcd more blah abcd a b c d more blah a b c d