Question

This snippet of Perl code in my program is giving the wrong result.

$condition ? $a = 2 : $a = 3 ;
print $a;

No matter what the value of $condition is, the output is always 3, how come?

Was it helpful?

Solution

This is explained in the Perl documentation.

Because of Perl operator precedence the statement is being parsed as

($condition ? $a= 2 : $a ) = 3 ;

Because the ?: operator produces an assignable result, 3 is assigned to the result of the condition.

When $condition is true this means ($a=2)=3 giving $a=3

When $condition is false this means ($a)=3 giving $a=3

The correct way to write this is

$a = ( $condition ? 2 : 3 );
print $a;

We got bitten by this at work, so I am posting here hoping others will find it useful.

OTHER TIPS

Once you have an inkling that you might be suffering from precedence problems, a trick to figure out what Perl thought you meant:

perl -MO=Deparse,-p -e '$condition ? $a= 2 : $a= 3 ; print $a;'

In your case, that'll show you:

(($condition ? ($a = 2) : $a) = 3);
print($a);
-e syntax OK

...at which point you should be saying "oh, that explains it"!

Just to extend the previous answer... If, for whatever reason, the assignments need to be part of the conditional, you'd want to write it thusly:

$condition ? ($a=2) : ($a=3);

This would be useful if you're assigning to different variables based on the condition.

$condition ? ($a=2) : ($b=3);

And if you're choosing the variable, but assigning the same thing no matter what, you could even do this:

($condition ? $a : $b) = 3;

Because of Perl operator precedence the statement is being parsed as:

($condition ? $a = 2 : $a ) = 3 ;

Because the ?: operator produces an assignable result, 3 is assigned to the result of the condition.

When $condition is true this means $a=2=3 giving $a=3

When $condition is false this means $a=3 giving $a=3

The correct way to write this is

$a = $condition ? 2 : 3;

In general, you should really get out of the habit of using conditionals to do assignment, as in the original example -- it's the sort of thing that leads to Perl getting a reputation for being write-only.

A good rule of thumb is that conditionals are only for simple values, never expressions with side effects. When you or someone else needs to read this code eight months from now, would you prefer it to read like this?

$x < 3 ? foo($x) : bar($y);

Or like this?

if ($x < 3) {
  $foo($x);
} else {
  $bar($y);
}

One suggestion to Tithonium's answer above:

If you are want to assign different values to the same variable, this might be better (the copy-book way):

$a = ($condition) ? 2 : 3;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top