I still remember a production incident where a Perl job silently skipped a data cleanup because a string that “looked true” wasn’t. The fix took five minutes; the postmortem took a day. That’s the thing about Perl booleans: there’s no dedicated boolean type, yet nearly every conditional in your code depends on truthiness. If you’re coming from languages with strict true and false, Perl can feel both powerful and slippery. You need a mental model that’s accurate, fast to apply, and grounded in real-world usage.
In this post I’ll walk you through Perl’s boolean behavior the way I explain it to teammates: what evaluates to true or false, why seemingly odd strings like "0\n" can be true, and how to write conditionals that don’t surprise you at 2 a.m. I’ll show runnable examples, discuss common mistakes, and share practical patterns I use in modern Perl codebases—especially when you integrate with today’s tooling and data pipelines. By the end, you’ll be able to predict Perl’s truthiness with confidence and design conditionals that make your intent clear to both the interpreter and your future self.
Truthiness in Perl: The Rules You Actually Use
Perl doesn’t ship with a distinct boolean type. Instead, Perl evaluates scalar values in a boolean context. Any conditional—if, unless, while, for, the ternary operator—asks the scalar: “Are you true?” The answer is determined by a small, strict set of false values. Everything else is true.
Here’s the rule set I keep in my head:
- False values are:
0(numeric zero),"0"(string zero),""(empty string), andundef. - Everything else is true.
That’s it. If you memorize only one rule about Perl booleans, make it that.
To see this in action, here’s a small, runnable script that checks a few typical values:
# perl
use strict;
use warnings;
my @values = (0, 1, 2, "0", "00", "", " ", "false", undef, "0\n");
for my $v (@values) {
my $label = defined $v ? "‘$v‘" : ‘undef‘;
if ($v) {
print "$label is True\n";
} else {
print "$label is False\n";
}
}
If you run this, you’ll see that 0, "0", "", and undef are false, while "00", " ", "false", and "0\n" are all true. That last one catches people: it looks like zero, but it’s a string containing the character 0 followed by a newline, so it isn’t the exact string "0", and therefore it’s true.
When I’m reviewing code, I treat any value that isn’t one of those four false values as true—even if it feels wrong at first. That mental shortcut keeps me from guessing.
Boolean Contexts: Where Perl Asks the Question
Perl doesn’t only evaluate booleans in if. There are many places where it silently requests a truthiness check. Knowing those spots helps you avoid accidental logic.
Common boolean contexts:
if,unlesswhile,until,forloops (when used as condition)- Logical operators
&&,||,and,or - Ternary operator
?: grep,map(when you return a value intended as a predicate)defined,existsdon’t directly check truthiness but are often used alongside it
Example with grep:
# perl
use strict;
use warnings;
my @ids = (101, 0, 204, "0", 305, undef, 406);
my @valid = grep { $_ } @ids;
print "Valid IDs: @valid\n";
This will remove 0, "0", and undef because those are false in boolean context. That might be what you want, but if 0 is a legitimate ID (it often is), the logic is wrong. That’s why I encourage explicit checks when the domain allows values that are falsey by Perl’s rules.
True Values: The Surprising “Yes” Values
Let’s talk about what Perl considers true beyond the obvious. Any non-zero number is true, and any string that is not exactly "" or "0" is also true.
Here are examples that often surprise developers new to Perl:
# perl
use strict;
use warnings;
my @truthy = (2, -1, 3.14, "00", "0\n", "false", " ", "no", "OFF");
for my $v (@truthy) {
if ($v) {
print "‘$v‘ is True\n";
}
}
All of those print as true. Perl doesn’t interpret the content of a string as semantic truth or falsehood. It uses exact string matching: only "0" and "" are false. So a string that says "false" is still true—because it isn’t the empty string and it isn’t exactly "0".
I like to use this as a teaching analogy: Perl is like a bouncer who checks only two IDs. If you aren’t empty or exactly 0, you’re in.
False Values: The Small, Precise Set
Perl’s false values are few, but the details matter. Here’s a canonical list with examples:
- Numeric zero:
0,0.0,0e0are false because numeric zero is zero. - String zero:
"0"is false because it’s exactly the string zero. - Empty string:
""is false. undef: undefined is false.
All of the following are false:
# perl
use strict;
use warnings;
my @falsey = (0, 0.0, "0", "", undef);
for my $v (@falsey) {
my $label = defined $v ? "‘$v‘" : ‘undef‘;
if ($v) {
print "$label is True\n";
} else {
print "$label is False\n";
}
}
If you do one thing to improve Perl code quality, make sure you can distinguish undef from "", and "0" from 0. They may be false in the same boolean check, but they often mean different things in your data model.
Numeric vs String Context: Why 0 and "0" Matter
Perl uses context heavily. A value can be interpreted numerically or as a string depending on how you use it. Boolean context is its own rule set, but it’s influenced by how you’ve built your logic.
Consider this scenario: you read user input from a file. You might get "0" or "00". In a numeric context, both convert to zero, but in boolean context "00" is true while "0" is false.
# perl
use strict;
use warnings;
my $input = "00";
if ($input) {
print "Boolean: true\n";
}
if ($input == 0) {
print "Numeric comparison: zero\n";
}
Both lines will print. That’s not a bug; it’s Perl telling you that numeric and boolean contexts are different. When I design conditionals, I ask myself whether I want numeric semantics or boolean semantics. If it’s numeric, I use == or !=. If it’s string, I use eq or ne. If it’s truthiness, I keep it as a bare scalar but I make sure the input domain doesn’t include "0" or "" as valid values.
In 2026-era codebases, I often see data coming from JSON, CSV, and database systems where booleans are encoded as strings or integers. When you parse these, you need explicit translation if you want reliable boolean behavior. I like to normalize early:
# perl
use strict;
use warnings;
sub normalize_bool {
my ($v) = @_;
return 0 if !defined $v;
return 0 if $v eq ‘‘;
return 0 if $v eq ‘0‘;
return 1; # anything else becomes true
}
That gives you deterministic behavior across mixed inputs.
Conditional Comparisons: eq, ==, and the Truth Trap
A classic Perl bug looks like this:
# perl
use strict;
use warnings;
my $status = "0";
if ($status == 0) {
print "Numeric zero\n";
}
if ($status) {
print "Truthy\n";
}
The output only prints “Numeric zero,” because $status is "0", which is false in boolean context. If you assume "0" is true because it’s a non-empty string, Perl will surprise you. It isn’t non-empty in Perl’s rule set; it’s a special-case false value.
When I write conditional comparisons, I ask two questions:
- Do I care about numeric meaning? Use
==and!=. - Do I care about string meaning? Use
eqandne.
When I just want to know if a value is present, I use defined and length to avoid ambiguity:
# perl
use strict;
use warnings;
my $input = "0";
if (defined $input && length $input) {
print "Value exists and is not empty\n";
} else {
print "Missing or empty\n";
}
That treats "0" as present, which is often the right call in APIs and data pipelines.
Common Mistakes and How I Avoid Them
Here are the mistakes I see most in code reviews, along with the patterns I recommend instead.
Mistake 1: Using boolean checks for presence
# perl
if ($user_id) {
# do something
}
If 0 is a valid ID, this fails. I prefer:
# perl
if (defined $user_id) {
# do something
}
Or, if empty strings are invalid:
# perl
if (defined $userid && length $userid) {
# do something
}
Mistake 2: Treating "false" as false
This isn’t a boolean parser:
# perl
my $flag = "false";
if ($flag) { # true
# unexpected behavior
}
If input comes from config or environment variables, I parse explicitly:
# perl
sub parse_bool {
my ($v) = @_;
return 0 if !defined $v;
return 1 if $v =~ /^(1
true yeson)$/i;
return 0 if $v =~ /^(0
false nooff)$/i;
return 0; # default to false if unrecognized
}
That avoids accidental truthiness in production config.
Mistake 3: Assuming undef and "" are interchangeable
They’re both false, but they mean different things. undef means “no value ever assigned,” while "" often means “explicitly blank.” When I’m dealing with user input, I preserve the difference as long as possible because it helps with validation and error reporting.
Real-World Scenarios: How Truthiness Bites
Let me ground this in three scenarios I’ve actually seen in modern Perl stacks.
Scenario 1: CSV imports and header rows
You import CSV and use a boolean check to skip bad rows:
# perl
if ($row->{email}) {
push @valid, $row;
}
If an email value is "0" due to malformed data, you silently drop it. That may be fine, but you lose an opportunity to report or fix the input. I prefer:
# perl
if (defined $row->{email} && length $row->{email}) {
push @valid, $row;
} else {
warn "Missing email at line $line\n";
}
Scenario 2: Feature flags from environment variables
Your deployment sets FEATURE_X=false and you do:
# perl
if ($ENV{FEATURE_X}) {
# enabled
}
That is true because the string "false" is true. Instead, parse your flag explicitly, even if it’s more code. It saves downtime.
Scenario 3: Database results where 0 is valid
Suppose you query a table where 0 is a legitimate count:
# perl
if ($count) {
print "Rows exist\n";
}
This fails for 0 even when the query succeeded. I recommend:
# perl
if (defined $count) {
print "Query succeeded, count = $count\n";
}
Then handle the count explicitly: if ($count > 0) or if ($count == 0).
Practical Patterns I Use in 2026 Codebases
Perl is alive in data tooling, sysadmin automation, legacy integrations, and performance-critical scripts. In 2026, many teams wrap Perl jobs with AI-assisted workflows or CI checks, and that makes clear boolean handling even more important. Here are patterns I use to keep logic clear and observable.
Pattern 1: Normalize external inputs immediately
Whenever data comes from JSON, environment, HTTP, or files, I normalize booleans early. This prevents downstream confusion.
# perl
sub normalizeenvflag {
my ($name) = @_;
my $raw = $ENV{$name};
return 0 if !defined $raw;
return 1 if $raw =~ /^(1
true yeson)$/i;
return 0;
}
my $dryrun = normalizeenvflag(‘DRYRUN‘);
Pattern 2: Use defined for presence, not truthiness
When I check for value presence, I don’t use a bare scalar. I use defined and length so that "0" and 0 are not mistaken for missing data.
Pattern 3: Be explicit in API contracts
If your function expects a boolean, document what values are accepted. I often accept 0/1, "0"/"1", true/false, yes/no, and parse them into 0 or 1 internally.
# perl
sub ensure_bool {
my ($v) = @_;
return 0 if !defined $v;
return 1 if $v =~ /^(1
true yeson)$/i;
return 0 if $v =~ /^(0
false nooff)$/i;
return 0;
}
Pattern 4: Use !! sparingly
The double-negation trick !!$v coerces a value into 1 or 0. It’s handy, but you need to remember Perl’s definition of false. It will treat "0" as false, which might be wrong for your input domain. I use it only after normalization.
Pattern 5: Log ambiguous values
When values can be ambiguous (like "0" or empty strings), I log them when I’m in a debugging phase. It’s cheap and it prevents hidden data drift.
Traditional vs Modern Approaches to Boolean Handling
Here’s how I think about old-school Perl style versus the kind of patterns I see in modern teams that mix Perl with CI, containers, and AI-generated configs.
Traditional
—
if ($ENV{FLAG})
if ($value)
defined $value and length $value Implicit truthiness
Strings passed raw
Ad-hoc manual runs
I recommend the modern approach because it’s explicit and resilient. It costs a few extra lines, but it saves hours of debugging.
Performance and Readability: Balancing Both
Boolean checks are very cheap in Perl; they typically operate in a few nanoseconds in most workloads. The performance cost you should watch is not the if itself but the ripple effect of unclear logic—extra retries, error handling, or bad data corrections that run later in the pipeline.
When I optimize for performance, I do these two things:
- Normalize once, early. After normalization, you can use bare boolean checks safely and quickly.
- Keep predicates short. Long conditionals are harder to reason about and harder to test.
For example, I prefer:
# perl
my $enabled = parsebool($ENV{FEATUREX});
if ($enabled) {
run_feature();
}
Over this:
# perl
if (defined $ENV{FEATUREX} && $ENV{FEATUREX} =~ /^(1
true yeson)$/i) {
run_feature();
}
Both are fast, but the first is readable and testable.
Testing Boolean Logic: Small Tests, Big Wins
In 2026 workflows, I often run Perl jobs inside CI with lightweight tests. Boolean logic is ideal for targeted unit tests because edge cases are easy to enumerate. I usually write a test table with input values and expected outputs.
# perl
use strict;
use warnings;
use Test::More;
sub parse_bool {
my ($v) = @_;
return 0 if !defined $v;
return 1 if $v =~ /^(1
true yeson)$/i;
return 0 if $v =~ /^(0
false nooff)$/i;
return 0;
}
my @cases = (
[undef, 0],
[‘‘, 0],
[‘0‘, 0],
[‘1‘, 1],
[‘true‘, 1],
[‘false‘, 0],
[‘yes‘, 1],
[‘no‘, 0],
[‘on‘, 1],
[‘off‘, 0],
[‘00‘, 0],
);
for my $case (@cases) {
my ($input, $expected) = @$case;
is(parsebool($input), $expected, "parsebool for " . (defined $input ? $input : ‘undef‘));
}
done_testing();
This is short, clear, and protects you from regressions when someone “simplifies” a boolean helper later. I’ve seen this save a production rollback more than once.
A Deeper Mental Model: Context, Coercion, and Intent
When Perl evaluates a scalar in a boolean context, it doesn’t “convert” it in the same way it does for numeric or string context. It asks the scalar for its truth value using a set of internal rules that are consistent but not always intuitive.
Here’s my simplified mental model:
- If it’s undefined, it’s false.
- If it’s a string, only
""and"0"are false. - If it’s numeric zero, it’s false.
- Otherwise, it’s true.
That model stays stable even if a value has been used in different contexts before. Perl internally stores values with flags indicating if they’re currently considered numeric or string. That’s one reason you can have cases where numeric comparisons and boolean checks behave differently from string comparisons. You don’t need to understand all internal details to write correct code, but you do need to acknowledge that “non-empty string” is not the same as “true.”
If you keep your intent clear—numeric check, string check, or truthiness check—Perl will do what you mean.
Edge Cases You Should Know (and Actually Test)
Most boolean surprises come from a handful of edge cases. Here are the ones I always keep in a test suite when I’m doing data-heavy work:
Edge Case 1: Whitespace-only strings
A string with spaces, tabs, or newlines is still true because it isn’t empty and isn’t exactly "0".
# perl
my $val = " \t\n";
if ($val) {
print "Whitespace is true\n";
}
This matters when you read data from CSV or fixed-width files. If you intend to treat whitespace as “empty,” you must trim it.
Edge Case 2: The string "0\n"
This looks like zero but it isn’t the exact string "0", so it’s true.
# perl
my $val = "0\n";
print $val ? "true\n" : "false\n"; # true
This is common when you read lines from a file and don’t chomp them.
Edge Case 3: Numeric zero stored as a string
"0" is false, but "00" is true even though it looks numeric.
# perl
for my $v ("0", "00", "000") {
print "$v => ", ($v ? "true" : "false"), "\n";
}
Edge Case 4: The string "0e0"
"0e0" is numerically zero. As a string, it isn’t exactly "0", but Perl treats it as numeric zero in many contexts. In boolean context, it’s false because it’s numerically zero.
# perl
my $v = "0e0";
print $v ? "true\n" : "false\n"; # false
This is a classic test case in Perl discussions. It looks like a non-empty string, but it’s still false because it represents zero numerically.
Edge Case 5: Objects with boolean overload
Objects can overload boolean context. That means if ($obj) can call custom logic. This is powerful but can surprise you if you’re not expecting it.
# perl
package Flag;
use overload ‘bool‘ => sub { $_[0]->{value} }, fallback => 1;
sub new { bless { value => $[1] }, $[0] }
package main;
my $f = Flag->new(0);
print $f ? "true\n" : "false\n"; # false
If you use libraries that overload boolean context, read their docs and don’t assume a plain scalar truthiness rule applies.
When NOT to Use Bare Truthiness
Bare truthiness is convenient, but it isn’t always safe. These are the cases where I avoid it:
- User IDs or numeric identifiers where
0is valid. - String flags coming from config or environment variables.
- Database query results where
0means something meaningful. - CSV or file data where whitespace or newlines can sneak in.
- External APIs that encode booleans as strings like
"false".
In those cases, I prefer explicit checks or normalization. I still use bare truthiness for internal booleans that I control and have already normalized, because it keeps the code clean.
A Practical Boolean Toolkit (Reusable Functions)
When I work on production scripts, I usually keep a small toolkit of boolean helpers. Nothing fancy, just consistent behavior.
1) A strict parser for configuration flags
# perl
sub parseboolstrict {
my ($v) = @_;
return 0 if !defined $v;
return 1 if $v =~ /^(1
true yeson)$/i;
return 0 if $v =~ /^(0
false nooff)$/i;
die "Invalid boolean value: $v";
}
Use this when you want to fail fast if the config is wrong. It’s ideal for deployment flags where ambiguity is dangerous.
2) A permissive parser with default
# perl
sub parsebooldefault {
my ($v, $default) = @_;
return $default if !defined $v || $v eq ‘‘;
return 1 if $v =~ /^(1
true yeson)$/i;
return 0 if $v =~ /^(0
false nooff)$/i;
return $default;
}
This is useful in scripts where you want to accept a wide range of values but still behave predictably.
3) A normalization function that returns 0/1
# perl
sub normalize_bool {
my ($v) = @_;
return 0 if !defined $v;
return 0 if $v eq ‘‘ || $v eq ‘0‘;
return 1;
}
This matches Perl’s own truthiness and is useful when you want a clean 0/1 value.
More Real-World Scenarios (and the Fixes I Use)
Scenario 4: HTTP query parameters
You receive a query parameter ?active=false and write:
# perl
my $active = $params->{active};
if ($active) {
# treat as active
}
This treats "false" as true. Instead, parse it:
# perl
my $active = parsebooldefault($params->{active}, 0);
Scenario 5: JSON data in ETL pipelines
Many JSON APIs encode booleans as true/false, but some encode them as strings. If you decode JSON in Perl, you might get actual booleans (from JSON modules) or strings, depending on the source. Normalize right away so downstream logic is consistent.
# perl
my $raw = $payload->{enabled};
my $enabled = parsebooldefault($raw, 0);
Scenario 6: Filesystem checks
You might be tempted to use truthiness to check file sizes or counts:
# perl
if (-s $file) {
print "File has content\n";
}
This is fine because -s returns size and 0 is false, but you should be aware that it’s a numeric check. If you also want to check the file exists, do it explicitly:
# perl
if (-e $file && -s $file) {
print "File exists and has content\n";
}
Scenario 7: Cache lookups
Suppose you use a cache where 0 is a valid stored value. A naive truthy check will treat it as “cache miss.”
# perl
my $value = $cache->get($key);
if ($value) {
# cache hit
}
Use defined instead:
# perl
if (defined $value) {
# cache hit, even if it‘s 0
}
Boolean Operators: &&/|| vs and/or
Perl has both &&/|| and and/or. They do the same logical operation but have different precedence. This matters for boolean expressions where you assign values or chain logic.
Example:
# perl
my $value = $a || $b;
This uses || with higher precedence, so it behaves like you’d expect: assign $a if true, else $b.
But:
# perl
my $value = $a or $b;
This is parsed as (my $value = $a) or $b; because or has lower precedence. That can lead to surprises in assignment or function calls.
I use || and && for most boolean expressions, and reserve and/or for control-flow style code where low precedence is intended, like:
# perl
open my $fh, ‘<', $path or die "Cannot open $path: $!";
That’s a classic, readable pattern. For everything else, I prefer ||/&& because they’re harder to misread.
Ternary Operators and Boolean Coercion
The ternary operator ?: is a neat way to normalize values:
# perl
my $flag = $raw ? 1 : 0;
This is equivalent to !!$raw, but many people find it clearer. It’s still subject to Perl’s truthiness rules, so if "0" is meaningful, normalize first.
Using defined and exists Properly
defined and exists are common companions to boolean logic, but they mean different things:
defined $xchecks if a scalar has a value assigned.exists $hash{key}checks if a key exists in a hash (even if the value isundef).
Example:
# perl
my %data = (a => 0, b => undef);
print "a exists\n" if exists $data{a};
print "b defined\n" if defined $data{b};
This prints “a exists” but not “b defined.” That distinction matters when you’re using exists to detect deliberate undef values (like “known but empty”) versus missing keys.
Cleanly Handling Boolean Outputs
Sometimes you need to output a boolean to JSON, logs, or another system. I usually prefer to output canonical values like 0/1 or true/false explicitly rather than relying on implicit stringification.
# perl
my $enabled = parsebooldefault($raw, 0);
print $enabled ? "true" : "false";
This makes logs and APIs easier to interpret and avoids confusion about "" or "0" values.
Debugging Boolean Bugs: My Checklist
When a Perl conditional behaves unexpectedly, I run through a quick checklist:
- Is the value
undef,"", or"0"? - Is there a trailing newline? (
"0\n"is true) - Is the value coming from external input? (Normalize it.)
- Am I using numeric or string comparison? (
==vseq) - Is an overloaded object involved? (Check docs.)
- Is precedence changing the logic? (
and/orvs&&/||)
Ninety percent of boolean issues I see fall into one of those buckets.
Alternative Approaches: Making Booleans Explicit
If you find Perl’s truthiness too implicit for a particular codebase, you can adopt a more explicit style. Here are two approaches I’ve seen work well:
Approach 1: Use dedicated boolean values from a module
Some Perl modules provide explicit boolean objects (often used in JSON libraries). These can improve clarity in API boundaries where boolean meaning is important. The cost is dependency and a slight learning curve for the team.
Approach 2: Standardize on 0/1 internally
Normalize everything to integers at the boundary, and treat internal logic as strictly 0/1. This works surprisingly well and reduces ambiguity. It’s also easy to test.
Example pattern:
# perl
my $enabled = parsebooldefault($raw, 0);
From here on, treat $enabled as 0 or 1 only
That keeps your boolean checks clean without relying on Perl’s broader truthiness rules.
Production Considerations: Deployments, Monitoring, and Data Drift
Boolean handling isn’t just a coding style issue—it has operational impact. In production, a misinterpreted boolean can toggle a feature, skip a cleanup, or drop records from a pipeline.
Here’s what I do to make boolean logic safe in production environments:
- Validate config at startup: Fail fast on invalid values.
- Log normalized flags: Make it obvious what your code thinks the boolean is.
- Add metrics for skipped branches: If a cleanup or migration is skipped, record a metric.
- Test with representative data: Include
"0","", andundefin fixtures. - Document accepted values: Especially for environment flags or API inputs.
These steps are cheap compared to the cost of a production incident.
A Practical “Truthiness Table” You Can Paste Into Docs
Sometimes I like to include a short truthiness table in internal docs so everyone on the team is aligned:
Boolean Context
—
undef false
"" false
"0" false
0 false
"0\n" true
"00" true
"false" true
" " true
1 true
-1 trueIt’s simple, but it prevents a surprising number of bugs.
Frequently Asked Questions (Short, Direct Answers)
Is "0" the only false non-empty string?
Yes. In Perl, the only non-empty string that is false is exactly "0". If there are other characters, even whitespace or newlines, it’s true.
Is "0e0" false or true?
It’s false because Perl treats it as numeric zero. This is one of the few counterintuitive cases that’s worth testing explicitly.
Can I rely on !!$v to normalize to booleans?
You can, but remember it follows Perl’s truthiness rules. If your input can be "0" and you want that to mean “present,” normalize first.
What about arrays and hashes in boolean context?
An array or hash in boolean context evaluates to its length (number of elements). Empty arrays/hashes are false; non-empty are true. This is convenient, but keep in mind it’s not the same as checking for undef.
Putting It All Together: A Safe Boolean Pattern
Here’s a short example that ties all the advice together. It takes raw input, normalizes it, and uses clear conditionals downstream:
# perl
use strict;
use warnings;
sub parsebooldefault {
my ($v, $default) = @_;
return $default if !defined $v || $v eq ‘‘;
return 1 if $v =~ /^(1
true yeson)$/i;
return 0 if $v =~ /^(0
false nooff)$/i;
return $default;
}
my $rawflag = $ENV{FEATUREX};
my $featureenabled = parsebooldefault($rawflag, 0);
if ($feature_enabled) {
print "Feature X is enabled\n";
} else {
print "Feature X is disabled\n";
}
It’s not flashy, but it’s reliable. That’s what you want from boolean logic.
Final Takeaways
If you remember nothing else, remember this: Perl’s false values are few and exact. Everything else is true. That gives you tremendous flexibility, but it also means you must be intentional about how you interpret inputs.
My personal rule: Use bare truthiness only when you control the data. For everything else, normalize or compare explicitly.
You can write safe, readable, modern Perl without fighting its boolean model. Once you internalize the rules and pick a small set of patterns, your code becomes more predictable—and your late-night incident rate drops to nearly zero.
If you want a single checklist to keep nearby, here’s mine:
- Know the four false values:
undef,"","0",0. - Normalize external inputs early.
- Use
definedandlengthfor presence. - Use
==for numeric comparisons,eqfor string comparisons. - Test edge cases like
"0\n"and"0e0".
Do that, and Perl’s boolean behavior becomes a tool rather than a trap.


