Operators#
Perl spells the boolean operators twice, in two different precedence
classes. The C-style symbolic forms (&&, ||, !) bind tightly;
the word forms (and, or, not) bind very loosely. There is
also // for the defined-or idiom, xor for exclusive-or, and
the ternary ?: which is logical selection in disguise.
The full inventory#
Operator |
Reads as |
Returns |
Precedence |
|---|---|---|---|
|
not |
normalised |
high |
|
and |
left if false, else right (the operand) |
high |
|
or |
left if true, else right (the operand) |
high |
|
defined-or |
left if defined, else right (the operand) |
high |
|
exclusive or |
normalised |
very low |
|
not |
normalised |
very low |
|
and |
left if false, else right (the operand) |
very low |
|
or |
left if true, else right (the operand) |
very low |
|
ternary |
middle if condition true, else right (operand) |
low |
Two things in this table do most of the work:
&&and||return an operand, not a boolean. This is the property that makes Perl’s idioms work the way they do. See below.The symbolic and word forms differ in precedence, not meaning.
&&andandcompute the same logical function. They differ in how tightly they bind to other operators around them. That is why you seeor dieafter function calls but||inside expressions — the chapter on theor dieidiom explains.
Short-circuit and the operand-return rule#
&& and || evaluate left-to-right and stop as soon as the result
is determined.
A && B— ifAis false, returnAwithout evaluatingB. Otherwise returnB.A || B— ifAis true, returnAwithout evaluatingB. Otherwise returnB.
Crucially, the return value is the operand itself, not a
normalised true/false. This is what makes patterns like
$config{port} || 8080 work: if $config{port} is set (truthy),
the expression is $config{port}’s value; if not, it is 8080.
my $port = $config{port} || 8080;
my $name = $user_input || "anonymous";
my $list = shift || [];
The same property powers or die:
open my $fh, '<', $path or die "open $path: $!";
# ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
# if open returns true, the right-hand operand
# the whole expression is never evaluated
# is true and we move on
open returns true on success, undef on failure. On success the
short-circuit stops on the left and die never runs. On failure
the right-hand operand evaluates, which is the die call.
// — defined-or#
|| treats 0, "", and "0" the same as undef. Sometimes
that is wrong: a configured 0 is a real value, not a missing one.
// short-circuits on definedness instead of truthiness:
A // B— ifAis defined, returnA. Otherwise returnB.
my $port = $config{port} || 8080; # 0 means "use default" — wrong
my $port = $config{port} // 8080; # 0 means "0", undef means "use default"
my $verbose = $opt{verbose} // 0; # 0 is a real choice
The compound assignment forms ||= and //= save you from
repeating the variable on the left:
$config{port} //= 8080; # set only if currently undef
$cache{$key} ||= compute($key); # set if currently false
xor and the absence of a high-precedence form#
There is no ^^ in Perl. xor exists only as the very-low-precedence
word form, and unlike and/or it does not short-circuit (it
cannot — both sides have to be evaluated to determine the result).
It returns a normalised 1 or "", not an operand.
if ($admin xor $guest) { ... } # exactly one of the two
For xor on values rather than on truthiness, the bitwise ^
applies to integers — covered in the applications chapter.
! and not#
Both negate. ! is the symbolic high-precedence form; not is the
word low-precedence form. Both return a normalised value: 1 for
“the operand was false”, empty string "" for “the operand was true”.
my $missing = ! $config{port}; # 1 if port is unset/0/""/"0"
return if not @items; # cleaner reading than `if !@items`
The ternary ?:#
COND ? X : Y is logical selection: if COND is true the value
is X, otherwise Y. It is not just sugar for an if/else
because it is an expression — it has a value, can be assigned,
returned, passed as an argument.
my $label = $count == 1 ? "1 item" : "$count items";
return $ok ? \%result : undef;
Beware nesting: $a ? $b : $c ? $d : $e parses as
$a ? $b : ($c ? $d : $e) — chained ?: is right-associative,
which is usually what you want for an if/elsif/else cascade but
is worth knowing rather than guessing.
Why the word forms exist: precedence, not style#
|| binds more tightly than =. or binds less tightly than =
(or ,, or anything else of conventional weight). That is the
entire reason the word forms exist.
my $fh = open $h, '<', $path || die "no $path: $!";
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
# parses as: open $h, '<', ($path || die "no $path: $!")
# which is: open the file named "either $path or the die-message"
# which is: catastrophe.
my $fh = open $h, '<', $path or die "no $path: $!";
# parses as: ($fh = open $h, '<', $path) or die "no $path: $!"
# which does what you meant.
Rule of thumb:
Inside an expression, where you want the value to flow into a variable or another operator: use
&&,||,!,//.After a statement, where you want a side-effect (
die,warn,return) to fire conditionally: useor,and,not.
What you should remember from this chapter#
&&and||are not predicates that return 1 or 0 — they return one of their operands. This is the foundation of||,||=,or die, and most short defaulting idioms.//is||for definedness, not truthiness. Use it when0is a legitimate value.The word forms exist to bind looser than assignment, not for style.
xorexists, has no symbolic form, does not short-circuit.