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#
Logical — short-circuit
&&and||, the alternative-without-iffamily.Boolean Logic — Operators —
?:in the context of all the boolean operators.Assignment —
?:as lvalue.