Ternary operator#

One operator, three operands. Logical selection as an expression — the result has a value, can be assigned, returned, passed as an argument.

Form#

COND ? THEN : ELSE

If COND is true, the value is THEN; otherwise it is ELSE. Only the chosen branch is evaluated:

my $label = $count == 1 ? "1 item" : "$count items";
return $ok ? \%result : undef;
my $abs   = $x < 0     ? -$x       : $x;

It is an expression, not a statement#

The most common reason to reach for ?: instead of if/else is that you want a value — to assign, to return, to put inside another expression:

# verbose
my $kind;
if ($n == 1) { $kind = 'singular' }
else         { $kind = 'plural'   }

# idiomatic
my $kind = $n == 1 ? 'singular' : 'plural';

Chaining (right-associative)#

A ? B : C ? D : E parses as A ? B : (C ? D : E) — the chain descends through the false branch:

my $sign = $x < 0  ? '-'
         : $x > 0  ? '+'
         :           '0';

The columnar layout makes the chain readable. Past two or three levels, switch to if/elsif/else — the chain stops being clearer than the alternative.

Ternary as lvalue#

Both branches must be lvalues, and the chosen branch is the lvalue you assign to:

my ($pos, $neg) = (0, 0);
($x > 0 ? $pos : $neg) = $x;             # assigns to $pos or $neg

# Common case: pick a buffer to append to
($verbose ? $log : $debug) .= "$msg\n";

This pattern is rare in modern code — an explicit if with two straightforward assignments reads better. Worth knowing for when you encounter it.

What you don’t write#

?: is not a statement separator. These are wrong:

$x ? do_a() : do_b();                    # OK: do_a/do_b have side-effects,
                                         # but the value is discarded
$x > 0 ? print "yes\n" : print "no\n";   # WORKS, but reads strangely

When the goal is a side-effect (rather than a value), use if/else or the postfix if/unless:

$x > 0 ? do_yes() : do_no();             # value-return phrasing
do_yes() if $x > 0;                       # side-effect phrasing
do_no()  unless $x > 0;

With short-circuit logical operators#

?: interacts with &&, ||, // in ways that can confuse the eye. Almost always parenthesise:

my $x = $a || $b ? $c : $d;              # parses as ($a || $b) ? $c : $d
                                         # because || binds tighter than ?:
my $x = $a || ($b ? $c : $d);            # if you meant the other thing,
                                         # parenthesise

Precedence#

?: sits at row 18 — looser than the boolean operators (&&/||///), tighter than assignment. This is why my $x = COND ? A : B works without parens around the right-hand side.

See also#