Search code examples
perllistscalar

Why do I get the last value in a list in scalar context in perl?


I had assumed that, in perl, $x=(2,3,4,5) and ($x)=(2,3,4,5) would give me the same result, but was surprised at what happened in my tests. I am wondering why this behavior is the way it is and why wantarray behaves differently. Here are my tests and the results:

>perl -e '$x=(1,2,3,5);print("$x\n")'
5
>perl -e '($x)=(1,2,3,5);print("$x\n")'
1
>perl -e '$x=(wantarray ? (1,2,3,5) : 4);print("$x\n")'
4
>perl -e '($x)=(wantarray ? (1,2,3,5) : 4);print("$x\n")'
4

Is this behavior consistent/reliable across all platforms?

Whoops. wantarray is for context of subroutine calls...

>perl -e '$x=test();sub test{return(1,2,3,5)};print("$x\n")'
5
>perl -e '($x)=test();sub test{return(1,2,3,5)};print("$x\n")'
1
>perl -e '$x=test();sub test{return(wantarray ? (1,2,3,5) : 4)};print("$x\n")'
4
>perl -e '($x)=test();sub test{return(wantarray ? (1,2,3,5) : 4)};print("$x\n")'
1

So I guess it is consistent, but why does the list return the last value in scalar context?


Solution

  • So I guess it is consistent, but why does the list return the last value in scalar context?

    Because it's useful.

    my $x = f() || ( warn('!!!'), 'default' );
    

    Well, more useful than any other alternative, at least. It's also consistent with its stronger cousin, ;.

    sub f { x(), y(), z() };
    

    is the same as

    sub f { x(); y(); z() };
    

    Each operator determines decides what it returns in both scalar and list context.[1]

    There are operators that only even return a single scalar.

    say time;             # Returns the number of seconds since epoch
    say scalar( time );   # Ditto.
    

    But operators that normally returns more than one scalar and those that return a variable number of scalars cannot possible return that in scalar context, so they will return something else. It's up to each one to decide what that is.

     say scalar( 4,5,6 );           # Last item evaluated in scalar context.
     say scalar( @a );              # Number of elements in @a.
     say scalar( grep f(), g() );   # Number of matching items.
     say scalar( localtime );       # Formatted timestamp.
    

    The list operator (e.g. x,y,z) returns what the last item of the list (z) returns when evaluated in scalar context. For example,

     my $x = (f(),g(),@a);
    

    is a weird way of writing

     f();
     g();
     my $x = @a;
    

    Notes

    1. Same goes for subs, though it's common to write subs that are useless to call in scalar context.