Skip to content
VLSI Mentor

Perl Part I · Module 8 · Conditional Statements

if / elsif / else

Conditionals in Perl look like conditionals everywhere else, with two differences that catch people on the first day and one that catches them later. The braces are not optional — a single-statement body still needs them, and leaving them off is a syntax error rather than a style warning. The keyword is spelled elsif, with no second e, and Perl is helpful enough to have a dedicated error message for the two spellings you are more likely to type. The one that catches people later is what Perl considers false, because the list is short, specific, and includes some strings that look like zero while excluding others that also look like zero.

Foundation14 min readPerlPart IControl FlowConditionals

Part I · Module 8 · Chapter 8.1 · if / elsif / else

1. The Shape

Azvya Education Pvt. Ltd.VLSI Mentor
bands.pl
use strict;
use warnings;

for my $n (12, 7, 1, -4) {
    if    ($n > 10) { print "$n: over ten\n" }
    elsif ($n > 5)  { print "$n: over five\n" }
    elsif ($n > 0)  { print "$n: positive\n" }
    else            { print "$n: zero or less\n" }
}
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
12: over ten
7: over five
1: positive
-4: zero or less

Only the first true branch runs. 7 is greater than 5 and greater than 0, and it printed one line. Once a branch matches, Perl skips the rest of the chain — which is why the order of the tests is part of the logic, not a detail. Reverse the first two branches here and 12 would report over five.

The comparison operators themselves come from Chapter 3.5 and Chapter 3.6: == != < > for numbers, eq ne lt gt for text. Getting that choice wrong is the single most common conditional bug in Perl and Chapter 3.5 is the chapter on it.

2. The Braces Are Mandatory

Azvya Education Pvt. Ltd.VLSI Mentor
nobraces.pl
use strict;
use warnings;

my $n = 5;

if ($n > 3) print "big\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
syntax error at nobraces.pl line 6, near ") print"
Execution of nobraces.pl aborted due to compilation errors.
Azvya Education Pvt. Ltd.VLSI Mentor
Measured exit status
255

C, C++, Java and SystemVerilog all allow a single statement with no braces. Perl does not. The body of an if is a block, and a block needs braces — there is no one-statement shortcut.

This is good news in practice, because the bodyless form is the cause of a well-known family of bugs in those other languages: add a second line to the body, forget to add braces, and the second line runs unconditionally. Perl makes that impossible.

If what you actually want is a one-line conditional, Perl has a different form for it — the statement modifier, which puts the condition at the end:

Azvya Education Pvt. Ltd.VLSI Mentor
The one-line form, covered in Chapter 8.3
print "big\n" if $n > 3;

That is Chapter 8.3's subject, and it is the idiomatic way to write a short guard.

3. It Is Spelled elsif

Perl has a dedicated error message for this, which tells you how often it is mistyped.

Azvya Education Pvt. Ltd.VLSI Mentor
elseif.pl
use strict;
use warnings;

my $n = 5;

if ($n > 9)        { print "huge\n" }
elseif ($n > 3)    { print "mid\n" }
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
elseif should be elsif at elseif.pl line 7.
syntax error at elseif.pl line 7, near ")    {"
Execution of elseif.pl aborted due to compilation errors.

The two-word form fails differently:

Azvya Education Pvt. Ltd.VLSI Mentor
elseif2.pl
use strict;
use warnings;

my $n = 5;

if ($n > 9)        { print "huge\n" }
else if ($n > 3)   { print "mid\n" }
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — STDERR
syntax error at elseif2.pl line 7, near "else if"
Execution of elseif2.pl aborted due to compilation errors.

elseif should be elsif names the fix outright. syntax error ... near "else if" does not, so the two-word habit from C costs a few more seconds. Both are compile errors, so neither can ship.

4. What Perl Considers False

This is the part that matters later, and the list is worth memorising because it is short.

Azvya Education Pvt. Ltd.VLSI Mentor
truth.pl
use strict;
use warnings;

my @cases = (
    [ q{0},        0        ],
    [ q{1},        1        ],
    [ q{-1},       -1       ],
    [ q{""},       ""       ],
    [ q{"0"},      "0"      ],
    [ q{"00"},     "00"     ],
    [ q{"0.0"},    "0.0"    ],
    [ q{"0E0"},    "0E0"    ],
    [ q{" "},      " "      ],
    [ q{"false"},  "false"  ],
    [ q{0.0},      0.0      ],
);
for my $c (@cases) {
    printf "%-9s is %s\n", $c->[0], ($c->[1] ? "TRUE" : "false");
}
my $u;
{ no warnings 'uninitialized'; printf "%-9s is %s\n", "undef", ($u ? "TRUE" : "false"); }
printf "%-9s is %s\n", "[]", ([] ? "TRUE" : "false");
printf "%-9s is %s\n", "empty \@a", (do { my @a; @a ? "TRUE" : "false" });
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
0         is false
1         is TRUE
-1        is TRUE
""        is false
"0"       is false
"00"      is TRUE
"0.0"     is TRUE
"0E0"     is TRUE
" "       is TRUE
"false"   is TRUE
0.0       is false
undef     is false
[]        is TRUE
empty @a  is false

Six things are false, and that is the whole list:

FalseNote
0the number zero
0.0because it is the number zero
""the empty string
"0"the one-character string zero
undefnever assigned, or explicitly undefined
an empty array or hashin boolean context

Everything else is true. In particular:

  • "00" is TRUE. Two characters, and not the exact string "0".
  • "0.0" is TRUE — a three-character string. Note 0.0 the number is false. The same-looking value behaves differently depending on whether it arrived as a number or as text, which is exactly what happens when a field is read from a report file.
  • " " is TRUE. A single space is a non-empty string.
  • "false" is TRUE, which surprises people coming from languages that have a real boolean type.
  • [] is TRUE — an empty array reference, which Chapter 7.1 §6 covered. if ($aref) and if (@$aref) ask different questions.

5. A Chain With No else

Azvya Education Pvt. Ltd.VLSI Mentor
noelse.pl
use strict;
use warnings;

my $slack = 0.34;

if ($slack < -0.1) { print "critical\n" }
elsif ($slack < 0) { print "marginal\n" }

print "done\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
done
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet

The else is optional, and when every condition is false, nothing happens and nothing is reported. That is correct behaviour and occasionally the bug.

A chain whose job is to classify something should usually end in an else — but be careful about what you expect that else to catch, because it is less than you would think.

Azvya Education Pvt. Ltd.VLSI Mentor
unreachable2.pl
use strict;
use warnings;

sub classify {
    my ($slack) = @_;
    no warnings 'uninitialized', 'numeric';
    return "critical"      if $slack < -0.1;
    return "marginal"      if $slack < 0;
    return "ok"            if $slack >= 0;
    return "UNCOMPARABLE";
}

my $nan = "nan" + 0;

printf "%-9s -> %s\n", "0.34",  classify(0.34);
printf "%-9s -> %s\n", "undef", classify(undef);
printf "%-9s -> %s\n", "N/A",   classify("N/A");
printf "%-9s -> %s\n", "NaN",   classify($nan);
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
0.34      -> ok
undef     -> ok
N/A       -> ok
NaN       -> UNCOMPARABLE

undef and "N/A" both came back ok. Only NaN reached the final branch.

Here is why, measured directly:

Azvya Education Pvt. Ltd.VLSI Mentor
Captured output — the three comparisons, per value
undef  : < -0.1 = false  < 0 = false  >= 0 = true 
N/A    : < -0.1 = false  < 0 = false  >= 0 = true 
NaN    : < -0.1 = false  < 0 = false  >= 0 = false

undef and "N/A" numify to 0, and 0 >= 0 is true — so they are classified as a passing slack. Across nine test values, exactly one made all three comparisons false, and that was NaN, whose incomparability Chapter 3.7 measured.

So the lesson is the opposite of the comfortable one. A final else on a chain of numeric comparisons is not a safety net for missing or malformed data — it catches a case you will almost never see, and lets through the two you will see constantly. Missing data does not announce itself by failing every comparison; it announces itself by quietly passing one.

A three-way classification cannot be built out of comparisons alone. It needs a different kind of test first:

Azvya Education Pvt. Ltd.VLSI Mentor
The shape that actually works
return "UNKNOWN"  unless defined $slack;
return "UNKNOWN"  unless $slack =~ /^[-+]?\d+(?:\.\d+)?$/;
return "critical" if $slack < -0.1;
return "marginal" if $slack < 0;
return "ok";

defined and a pattern match answer "do I have a usable number", and only then do the comparisons get to answer "which band". Chapter 8.6 is the whole chapter on that ordering, and it measures what a check without it reports.

6. Why This Matters in Engineering Work

Branch order is logic. An elsif chain that classifies by threshold must run from the narrowest condition outward. Written the other way round it still compiles, still runs, and reports every critical violation as merely marginal.

The false list decides what your guards do. if ($count) skips a block with zero items, which is usually what you want. if ($slack) skips a path with exactly zero slack, which is almost never what you want — and a slack of zero is a perfectly ordinary timing result.

And text from a file is text. The single most common source of a conditional that behaves differently in production than in your test is a value that was a number when you typed it and a string when the tool produced it. defined, a pattern match, or a numeric comparison all avoid it; a bare truth test does not.

7. Common Mistakes

Omitting the braces. Perl has no bodyless if. Use a statement modifier for a one-liner.

elseif or else if. The keyword is elsif. Perl names the fix for the first form only.

Ordering an elsif chain from widest to narrowest. The first match wins, so the narrow cases never run.

if ($value) to test presence. Use defined. 0, "0" and "" are all present and all false.

Expecting "0.0" to be false. The string is true; the number is false.

Expecting "00" or " " to be false. Both are true.

Reaching for given/when. It is experimental and warns on every run. Use an elsif chain or a dispatch table.

A classifying chain with no else. When nothing matches, nothing happens and nothing is reported.

8. Exercise

Exercise 1 — the chain. Write a four-branch chain that classifies 12, 7, 1 and -4 as over ten, over five, positive, or zero-or-less. Confirm each input produces exactly one line.

Exercise 2 — order matters. Swap the first two branches and rerun. Record what 12 now reports and explain it in one sentence using the phrase "first match".

Exercise 3 — no braces. Write if ($n > 3) print "big\n"; and record the exact error and exit status. Then rewrite it as a one-liner using a statement modifier.

Exercise 4 — both typos. Write elseif and then else if. Record both diagnostics and note which one tells you the fix.

Exercise 5 — the truth table. Test all fourteen values from §4. Write down the six that are false. Then explain in one sentence why 0.0 is false but "0.0" is true.

Exercise 6 — the file-versus-arithmetic trap. Set one variable to the string "0.0" and another to the number 0.0. Print whether each is true. Then write the three questions from §4's callout — defined, a numeric comparison, and a pattern match — and say which you would put in a report script.

Exercise 7 — given/when. Run §3's given/when example. Record STDOUT and STDERR. Write one sentence on why you would not put it in a shared script.

Exercise 8 — what the final else actually catches. Write §5's three-branch slack classifier with a final branch returning UNCOMPARABLE. Call it with 0.34, undef, the string "N/A", and "nan" + 0. Record which of the four reached the last branch. Then, for the three non-numeric inputs, print each of the three comparisons separately and explain in one sentence why two of them were classified ok. Finally rewrite the classifier with a defined test and a numeric pattern match in front, and confirm all three now report UNKNOWN.

9. Summary

  • if / elsif / else, and only the first true branch runs. Branch order is part of the logic.
  • The braces are mandatory, even for one statement. Omitting them is a syntax error, exit 255.
  • The keyword is elsif. elseif gets a dedicated elseif should be elsif diagnostic; else if gets a plain syntax error.
  • Exactly six things are false: 0, 0.0, "", "0", undef, and an empty array or hash.
  • "00", "0.0", "0E0", " ", "false" and [] are all true.
  • 0.0 is false but "0.0" is true — the same value from a file behaves differently from the same value from arithmetic.
  • Test presence with defined, not with truth.
  • given/when is experimental and warns every run. Use an elsif chain, or Chapter 7.11's dispatch table when the cases are many.
  • A classifying chain should end in an else, because undef and non-numeric text make every comparison false.

Chapter 8.2 covers the same decision written the other way round: unless, which runs a block when a condition is false, and the point past which it stops being easier to read.

Where this fits

Part of the Perl curriculum.