Search code examples
perlconditional-operator

Perl conditional (ternary) operator does no shortcut evaluation


The conditional (ternary) operator suggests the ternary operator is a substitute for if ... else. I always thought so, but recently I have a logical problem with that.

Consider this short debug session:

  DB<1> $s='X'

  DB<2>  1 ? $s .= '_' : $s = '_'

  DB<3> x $s
0  '_'

So if 1 is true, then the expression $s .= '_' should be evaluated (and not $s = '_').

But why is $s just '_' at the end?


Solution

  • The ternary conditional operator (?:) has a higher precedence than the assignment operator (=) (the table of the precedence of Perl's operator can be found in the Operator Precedence and Associativity section of perlop). As such, the line

    1 ? $s .= '_' : $s = '_'
    

    is parsed by Perl as

    (1 ? ($s .= '_') : $s) = '_'
    

    (You can check that by yourself by running perl -MO=Deparse <your program>)

    Note also that $s .= '_' returns $s with the added _ at the end, and that this $s can be assigned to (in technical terms, it's an lvalue). This is documented in the Assignment Operators section of perlop:

    Unlike in C, the scalar assignment operator produces a valid lvalue. Modifying an assignment is equivalent to doing the assignment and then modifying the variable that was assigned to.

    So, basically, your code is doing

    ($s .= '_') = '_';
    

    Which is equivalent to

    $s .= '_';
    $s = '_';