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

Thank you all. I have already got the answer from your replies.

I know that I can't take reference to the return value of a subroutine directly. But I want to know why? Here is an example.

sub foo{ return (0, 1); } my $var = \(foo()); # $var is not a reference to the array (0, 1).

Replies are listed 'Best First'.
Re: Reference to return value of a subroutine
by haukex (Archbishop) on Apr 02, 2017 at 14:25 UTC
    the array (0, 1)

    I think this might be the misunderstanding here: (0, 1) isn't an array, in this form it's a literal list. While you obviously use lists to populate arrays, arrays and literal lists behave differently in different contexts. For example, an array in scalar context returns its size, whereas a list returns its last value, and taking a reference to an array creates an arrayref, while taking a reference to a list works as follows.

    What is going on here is that your sub foo is returning the list (0, 1), and the \ (backslash) referencing operator is "distributive" when applied to lists, meaning that \(0, 1) is the same thing as (\0, \1). So your assignment basically becomes my $var = (\0, \1);. Then, the Comma Operator in scalar context "evaluates its left argument, throws that value away, then evaluates its right argument and returns that value", which is why $var is being assigned \1.

    You could do several things, as the other monks have shown: [foo()], return [0, 1], or also possible would be return \@array. However, note that \ has a special-case behavior which means that sub foo { my @array = (0,1); return @array }; my $var = \(foo()); would not work, as "\(@foo) returns a list of references to the contents of @foo, not a reference to @foo itself." (perlref).

    Update: See also this recent thread, the FAQ What is the difference between a list and an array?, and perhaps one or two other PerlMonks threads such as What is the difference between a list and an array?.

Re: Reference to return value of a subroutine
by golux (Chaplain) on Apr 02, 2017 at 13:56 UTC
    You can take the reference of a subroutine's return value. You did just that, and can see it with:
    use feature qw( say ); use Data::Dumper; sub foo{ return (0, 1); } my $var = \(foo()); # $var IS a reference to the last item of *list* +(0, 1) say Dumper($var); # Prints $VAR = \1;

    To make it more obvious, try this:

    sub foo{ return ('blue', 'green'); } my $var = \(foo()); say Dumper($var); # Prints $VAR = \'green';

    What's happening is that you're returning a list that gets evaluated in scalar context, whose behavior is to take the last item of the list.

    If you want to capture the whole list, try returning an ARRAY reference instead (then you don't even need the extra reference):

    use feature qw( say ); use Data::Dumper; sub foo{ return [ 'blue', 'green' ]; } my $var = foo(); # Give me my ARRAY ref! say Dumper($var); # Prints $VAR1 = [ # 'blue', # 'green' # ];
    say  substr+lc crypt(qw $i3 SI$),4,5
Re: Reference to return value of a subroutine
by stevieb (Canon) on Apr 02, 2017 at 13:49 UTC

    Well, you can, but you just have to use an alternate syntax:

    my $var = [foo()];

    In this case, you should know in advance that foo() returns a list that you want to take as an array reference. If a scalar is returned, it will automatically be populated as the first element in the array reference, regardless of its type.

Re: Reference to return value of a subroutine
by huck (Prior) on Apr 02, 2017 at 13:52 UTC

    Does this help

    use strict; use warnings; sub foo{ return (0, 1); } my $ct=0; { print "\nct:".$ct++."\n"; my $var = \(foo()); # $var is not a reference to the array (0, 1). bu +t to the rightmost scalar print $var."\n"; print $$var."\n"; } { print "\nct:".$ct++."\n"; my $var = (foo()); # $var is the rightmost of list print $var."\n"; } { print "\nct:".$ct++."\n"; my ($var) = (foo()); # $var is the leftmost of list print $var."\n"; } { print "\nct:".$ct++."\n"; my $var = [foo()]; # $var is array reference print $var."\n"; }
    Result
    ct:0 SCALAR(0x3f7f2c) 1 ct:1 1 ct:2 0 ct:3 ARRAY(0x3f7f44)

Re: Reference to return value of a subroutine
by davido (Cardinal) on Apr 02, 2017 at 16:56 UTC

    Your example code takes a reference to each individual list element returned by foo(), and then retains the last one.

    If you want a reference to an array, you have two choices. First, you could modify the subroutine to return a reference to an array:

    sub foo { return [0,1]; } my $aref = foo();

    Second, you could instantiate an array reference upon receiving the return value of the subroutine:

    sub foo { return (0,1); } my $aref = [foo()];

    In the second example, the [...] square brackets are creating a reference to an anonymous array that is being populated by the list returned from foo().

    For large lists, the first example could be more efficient since it passes a single value (the array reference) back from the subroutine call, rather than a potentially large list which must then be pulled into a new reference. We all love to hate wantarray, but how about this?

    sub foo { my @rv = (0,1); return wantarray() ? @rv : \@rv; } my $aref = [foo()]; # wantarray() will be true, so the entire list ge +ts passed back and then the square braces create and populate an arra +y ref. my $aref2 = foo(); # wantarray() will be false, so inside the subrou +tine we return a reference to the array.

    Yeah.... that code kind of smells because it has a strong potential of surprising the caller. Just a thought, but you'll probably want the first or second example and just keep the third as an example of something that Perl can do but maybe shouldn't. ;)


    Dave

      We all love to hate wantarray

      This is flat out wrong. I for one don't. wantarray is probably the most perlish of all functions, since it is the most linguistic one. It gives elements (subroutines) which are ambiguous the ability to reveal their meaning depending on context. Bank of England, river bank, mining bank (this is itself ambiguous), bank of a billard table, battery bank, road bank - in all elements of this comma separated list the word 'bank' chooses its appropriate meaning out of all possibilities depending on its context.

      It is the only function which makes perl's ambiguity and context awareness useful for the programmer. Without a way to determine the calling context inside a sub, all the context sensivity of perl would be just a nuisance, and we would do better without it. So, wantarray is at the core of one of perl's most fundamental concepts.

      If I hated the core of perl, I'd probably program python.

      Yeah.... that code kind of smells because it has a strong potential of surprising the caller.

      Why? Does localtime smell, because it may be surprising for the caller? And then - what is more surprising for someone: a) getting the last element of the returned list, in scalar context, or b) getting a scalar reference to an array holding the elements of the returned list?

      It is all a matter of taste, convention and documentation, e.g. this

      foo() - this function returns a list of bars. When called in scalar context, you get the last element by default.
      If you want some other element, index the returned list, e.g. $thisbar = (foo($blorf))[2];

      or this

      foo() - this function returns a list of bars. If called in scalar context, it returns a reference to an array holding that list.

      Quick, which one is more intuitive for the unaware?

      So no, there is no smell here, except for those who are ashamed of some aspects of perl which are its core features and rather would weed out all ambiguities and clamp it all under the harness of e.g. PerlCritic.

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'