0

I am confused with operator precedence in Perl. I have expression like:

$a || $b ? join ",", @$b : ""

I thought Perl would create a list context:

my $result = $a || ($b ? join ",", @$b : ""); 
# I thought (...) would create a list context and make result = 1,
# but $result is correctly set to the join of @$b
# Why does it not create list context?
SwiftMango
  • 15,092
  • 13
  • 71
  • 136
  • Just out of curiosity, what exactly are you trying to achieve? Is this related to your earlier question about using either `@ARGV` or `STDIN`? A more concrete example would be nice. In general, I would only use the conditional operator for very simple cases, since it is a little harder to mentally parse than a simple `if`/`else`. – ThisSuitIsBlackNot Mar 22 '15 at 05:53
  • @thissuitisblacknot well they are not quite related but they are the problems I had in one project. if else is always a universal solution of course but I just wanna know some dirty hacks of perl – SwiftMango Mar 22 '15 at 06:18

1 Answers1

2

From the section on context in perldoc perldata:

Assignment is a little bit special in that it uses its left argument to determine the context for the right argument. Assignment to a scalar evaluates the right-hand side in scalar context, while assignment to an array or hash evaluates the righthand side in list context. Assignment to a list (or slice, which is just a list anyway) also evaluates the right-hand side in list context.

(emphasis added)

And from perldoc perlop:

Conditional Operator

[...]

Scalar or list context propagates downward into the 2nd or 3rd argument, whichever is selected.

$a = $ok ? $b : $c;  # get a scalar
@a = $ok ? @b : @c;  # get an array
$a = $ok ? @b : @c;  # oops, that's just a count!

As for precedence, || has a higher precedence than the conditional operator, so

my $result = $foo || $bar ? 0 : 1;

is equivalent to

my $result = ($foo || $bar) ? 0 : 1;

Note that the parentheses do not create list context, which is a common misconception. They aren't necessary in this case, but they do improve readability, so I would recommend using them.

Again, in

my $result = $foo || ($bar ? 0 : 1);

parentheses do not create list context. With ||

Scalar or list context propagates down to the right operand if it is evaluated.

so ($bar ? 0 : 1) is evaluated in scalar context (assuming $foo is a true value; if not, || short-circuits and the RHS isn't evaluated at all).

ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110
  • Parentheses do not create list context? What do they do? – SwiftMango Mar 22 '15 at 06:06
  • @texasbruce In this case, the parentheses are simply used for grouping; they simply affect precedence. Also, don't confuse list *values* with list *context*. See [List value constructors](http://perldoc.perl.org/perldata.html#List-value-constructors) in `perldoc perldata`. – ThisSuitIsBlackNot Mar 22 '15 at 06:34
  • 1
    @texasbruce Also see [ikegami's answer to "Can the empty list be in scalar context?"](http://stackoverflow.com/a/6970812/176646) and the [Scalar vs List Assignment Operator](http://www.perlmonks.org/?node_id=790129) tutorial on PerlMonks. It's a common misconception that parentheses create a list; they don't. The posts I linked explain two frequent sources of confusion: `my $foo = ();` (the `()` is not actually a list, although it is sometimes called the null list or empty list); and `my ($foo) = ...` – ThisSuitIsBlackNot Mar 22 '15 at 13:38