Truthiness#

Before logic, the values logic operates on. Perl does not have a dedicated boolean type. Every scalar is either true or false when used in boolean context, and the rule is short:

A scalar is false if it is one of the four values undef, the integer 0, the string "", or the string "0". Everything else is true.

Four false values, every other scalar — including the strings "00", "0.0", "0E0", and "false" — is true.

if (0)        { ... }   # false  -- the integer zero
if (0.0)      { ... }   # false  -- numerically zero
if ("")       { ... }   # false  -- empty string
if ("0")      { ... }   # false  -- the string "0"
if (undef)    { ... }   # false  -- undefined value

if ("00")     { ... }   # TRUE   -- non-empty, not the string "0"
if ("0.0")    { ... }   # TRUE   -- non-empty, not the string "0"
if ("0 but true") { ... } # TRUE -- non-empty, not the string "0"
if (" ")      { ... }   # TRUE   -- single space is non-empty
if ("false")  { ... }   # TRUE   -- it's just a 5-character string

The "0 but true" idiom is not a joke. Some Perl APIs return a value that must compare equal to zero numerically (so an arithmetic test does the right thing) but be true in a boolean context. The classical case is ioctl() — success returning literally zero would test false. The string "0 but true" is numerically zero (with a warning suppressed by historical agreement) and boolean-true because it is not in the four-element false set.

my $rc = ioctl($fh, $cmd, $buf);
$rc == 0       and warn "numeric zero";   # would fire on success
$rc            or  warn "boolean false";  # FIRES if API returned 0
                                          # but NOT if "0 but true"

Two flavours of comparison#

Perl has parallel families of comparison operators because it has parallel notions of equality. Numbers compare numerically; strings compare lexically. The wrong family on the wrong type is one of the most common bugs in beginner Perl.

Test

Numeric

String

equal

==

eq

not equal

!=

ne

less than

<

lt

greater than

>

gt

less or equal

<=

le

greater or equal

>=

ge

three-way (sort)

<=>

cmp

== on strings always succeeds for any two non-numeric strings — both convert to 0, and 0 == 0 is true:

"foo" == "bar";    # TRUE  -- both stringify to numeric 0
"foo" eq "bar";    # FALSE -- the actual question

"10" eq 10;        # TRUE  -- string "10" equals numeric 10 stringified
"10" == 10;        # TRUE  -- 10 == 10 numerically
"10" lt "9";       # TRUE  -- lexical: "1" < "9"
"10" <  "9";       # FALSE -- numeric: 10 > 9

<=> and cmp return -1, 0, or +1 — the standard sort comparator shape. They are not boolean operators in the strict sense, but they appear inside boolean contexts often enough that you should know them.

Why this matters for logic#

Every boolean operator in Perl — &&, ||, //, !, xor, and, or, not — uses the four-value false set above as its input rule. Whenever a chapter below says “if $x is false”, that is exactly what is meant: $x is undef, 0, "", or "0". Whenever it says “if $x is true”, $x is anything else.

Two consequences worth keeping in mind:

  1. A scalar can be true without being a boolean true value. Strings, references, blessed objects, large numbers — all true. When you ask “is this true?” you are not asking “does this equal 1?” — you are asking “is this not in the false set?”.

  2. The result of a boolean operator is not always 1 or 0. The next chapter covers this in detail. Briefly: && and || return one of their operands, not a normalised boolean. This is a feature, not a quirk, and many Perl idioms depend on it.