views:

97

answers:

2

In perl, parentheses are used for overriding precedence (as in most programming languages) as well as for creating lists. How can I tell if a particular pair of parens will be treated as a grouping construct or a one-element list?

For example, I'm pretty sure this is a scalar and not a one-element list: (1 + 1)
But what about more complex expressions? Is there an easy way to tell?

+15  A: 

Three key principles are useful here:

Context is king. The evaluation of your example (1 + 1) depends on the context.

$x = (1 + 1); # Scalar context. $x will equal 2. Parentheses do nothing here.
@y = (1 + 1); # List context. @y will contain one element: (2).
              # Parens do nothing (see below), aside from following 
              # syntax conventions.

In a scalar context, there is no such thing as a list. To see this, try to assign what appears to be a list to a scalar variable. The way to think about this is to focus on the behavior of the comma operator: in scalar context it evaluates its left argument, throws that value away, then evaluates its right argument, and returns that value. In list context, the comma operator inserts both arguments into the list.

@arr  = (12, 34, 56); # Right side returns a list.

$x    = (12, 34, 56); # Right side returns 56. Also, we get warnings
                      # about 12 and 34 being used in void context.

$x = (@arr, 7);       # Right side returns 7. And we get a warning
                      # about using an array in a void context.

Parentheses do not create lists. The comma operator creates the list (provided that we are in list context). When typing lists in Perl code, the parentheses are needed for precedence reasons -- not for list-creation reasons. A few examples:

  • The parentheses have no effect: we are evaluating an array in scalar context, so the right side returns the array size.

    $x = (@arr);
    
  • Parentheses are not needed to create a list with one element.

    @arr = 33;         # Works fine, with @arr equal to (33).
    
  • But parentheses are needed with multiple items -- for precedence reasons.

    @arr = 12, 34, 56; # @arr equals (12). And we get warnings about using
                       # 34 and 56 in void context.
    
FM
+9  A: 
  1. Context.
  2. Parentheses don't have the role you think they have in creating a list.

Examples:

$x = 1 + 1;   # $x is 2.
$x = (1 + 1); # $x is 2.
@x = 1 + 1;   # @x is (2).
@x = (1 + 1); # @x is (2).

$x = (1 + 1, 1 + 2); # $x is 3.
@x = (1 + 1, 1 + 2); # @x is (2, 3).

Roughly speaking, in list context the comma operator separates items of a list; in scalar context the comma operator is the C "serial comma", which evaluates its left and right sides, and returns the value of the right side. In scalar context, parentheses group expressions to override the order of operations, and in list context, parentheses do... the exact same thing, really. The reason they're relevant in assigning to arrays is this:

# Comma has precedence below assignment. 
# @a is assigned (1), 2 and 3 are discarded.
@a = 1, 2, 3; 

# @a is (1, 2, 3).
@a = (1, 2, 3);

As for your question "is it a scalar or a one-element list", it's just not a meaningful question to ask of an expression in isolation, because of context. In list context, everything is a list; in scalar context, nothing is.

Recommended reading: perlop, perldata, Programming Perl.

hobbs
I like Deparse to show that comma operator: perl -MO=Deparse -le 'my @s = 1,3,4; print "@s"'BEGIN { $/ = "\n"; $\ = "\n"; }my(@s) = 1, '???', '???';print "@s";-e syntax OK
brian d foy