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

I've got a short question about how Perl handles return values.

I've got a subroutine that returns multiple values, but in several cases I only need a subset of these values when calling the subroutine.

My question is: How can I specify which ones I want? Please have a look at this short example:

my $result = get_values(); sub get_values { return (“a”, “b”, “c”); }

In my testing $result always gets the value "c" (I assume because it's the last value). But is this guaranteed? Where is this documented? I didn't find anything at http://perldoc.perl.org/perlsub.html or http://perldoc.perl.org/functions/return.html and also perlmonks' search didn't help me out.

And taking this one step further: How can I get "a" and "c"? I know that I can just use three variables and ignore the second one, but I guess there's a better way to do that.

Thanks!

Replies are listed 'Best First'.
Re: Ignore certain return values
by bart (Canon) on Oct 21, 2008 at 01:10 UTC
    In my testing $result always gets the value "c" (I assume because it's the last value). But is this guaranteed? Where is this documented?
    Look at the comma operator in perlop:
    Binary "," is the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value. This is just like C's comma operator.
    So yes, if you have several of those comma operations in a row, you'll end up with the last value.

    Do note that if you first put them values in an array and return that, you get something else entirely back: the number of elements in the array.

    sub get_values { my @a = ("a", "b", "c"); return @a } $x = get_values; # 3
    And taking this one step further: How can I get "a" and "c"? I know that I can just use three variables and ignore the second one, but I guess there's a better way to do that.
    Use a slice on the list, just like you would do with an array. For that, you must wrap the function call in parens:
    my @some = (get_values)[0,2];
Re: Ignore certain return values
by ikegami (Patriarch) on Oct 21, 2008 at 07:41 UTC

    But is this guaranteed?

    No, not from the perspective of the sub's caller. It's dependent on the implementation of the sub.

    For example, consider the following two functions that behave identically in list context.

    >perl -le"sub f { 'a','b','c' } my @v=f(); print for @v" a b c >perl -le"sub f { my @a = ('a','b','c'); @a } my @v=f(); print for @v" a b c

    In scalar context, however, they return drastically different results.

    >perl -le"sub f { 'a','b','c' } my $v=f(); print $v" c >perl -le"sub f { my @a = ('a','b','c'); @a } my $v=f(); print $v" 3

    If the sub doesn't define how it behaves in scalar context (which is the case for many subs that return lists), you have two options.

    • You can assign to a list with the undesired elements undefined.

      (my $first) = f(); (my $first, undef, my $third) = f(); (undef, my $second) = f();

      The above can also be written as

      my ($first) = f(); my ($first, undef, $third) = f(); my (undef, $second) = f();
    • You can filter out the undesired returned values. This is usually done using a list slice (see perldata).

      my $first = ( f() )[0]; my ($first, $third) = ( f() )[1,3]; my $second = ( f() )[2];
Re: Ignore certain return values
by Cristoforo (Curate) on Oct 21, 2008 at 01:14 UTC
    You are getting 'c' in scalar context because of the behavior of the comma operator, http://perldoc.perl.org/perlop.html#Comma-Operator. To control how your sub returns values in a scalar or list context, see function wantarray.

    For your last question, you could do something like
    my ($first, $third) = (get_values())[0,2];

    Chris

Re: Ignore certain return values
by GrandFather (Saint) on Oct 21, 2008 at 02:05 UTC

    The calling context is important. Consider:

    use warnings; use strict; my $result = get_values (); print "$result\n"; my @results = get_values (); print "@results"; sub get_values { return ("a", "b", "c"); }

    Prints:

    c a b c

    Perl reduces RSI - it saves typing
Re: Ignore certain return values
by andreas1234567 (Vicar) on Oct 21, 2008 at 07:27 UTC
    Note the difference between $result = get_values() and ($result) = get_values()
    $ perl -wl sub get_values { return ('a', 'b', 'c'); } my $result = undef; $result = get_values(); print $result; ($result) = get_values(); print $result; __END__ c a
    You should be aware of Context (perl.com). The wantarray builtin tells you the calling context:
    $ perl sub check_context { # True if ( wantarray ) { print "List context\n"; } # False, but defined elsif ( defined wantarray ) { print "Scalar context\n"; } # False and undefined else { print "Void context\n"; } } my @x = check_context(); # prints 'List context' my %x = check_context(); # prints 'List context' my ($x, $y) = check_context(); # prints 'List context' my $x = check_context(); # prints 'Scalar context' check_context(); # prints 'Void context' __END__ List context List context List context Scalar context Void context
    There are several modules that addresses context and return values, e.g. Contextual::Return.
    --
    No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
Re: Ignore certain return values
by repellent (Priest) on Oct 21, 2008 at 03:34 UTC