The
if statement is known well to all but the most inexperienced Perl newbie. That's not pejorative: I was nearly that inexperienced myself when I wrote this, and did so as a means of self-education.
There's more to
if statements than immediately meets the eye, though. They are control structures — ordered segments of algorithm — that can take several forms and be used in a number of different ways. They are, in short, boolean conditionals: either/or decisions leading to execution of further instructions.
if
The first thing the most basic
if statement does is test for the truth of an expression. That expression is the "control statement" of the
if statement. When the expression is evaluated as true, the code in the statement block is executed: when it is evaluated as false, the code in the statement block is ignored. Example:
if ($foo == 7)
{
$foo++;
}
In the above example, the control statement expression is
$foo == 7. If the contents of the scalar
$foo are equal to 7, it evaluates as true, and the code within the statement block (delimited by the braces) is executed. If the contents of the scalar
$foo are equal to some other number or string, or
$foo is undefined, the code within that statement block is not executed. Thus:
#!/usr/bin/perl -w
use strict;
my $foo;
$foo = 7;
if ($foo == 7)
{
$foo++;
}
print($foo);
In the above example, executing the program simply causes the numeral 8 to be printed to STDOUT, which is normally the screen. (Typically you'd want to include a newline in what you print to STDOUT in a program like this, but it's not relevant to the example.) Meanwhile, in the following example, the STDOUT output is the numeral 6, because the increment operation
$foo++ is not executed when the control statement is evaluated as false:
#!/usr/bin/perl -w
use strict;
my $foo;
$foo = 6;
if ($foo == 7)
{
$foo++;
}
print($foo);
That, of course, is all very basic. It gets slightly more interesting from here.
unless
The
unless statement is a reversal of the control statement in an
if statement. For instance, where above the control statement
$foo == 7 causes the
if statement block to be executed if evaluated as true, the code in the
unless statement block is executed only if the control statement is evaluated as false. Thus,
unless ($foo == 7) achieves exactly the same result as
if ($foo != 7). The same is true, when working with strings, of the
eq and
ne operators.
if, reversed
Another way to represent an
if statement is to use a one-line reversal of the normal order of it. Just as in English one can say both "If this happens, that follows," and "that follows if this happens," so too can you switch the order of expressions in an
if statement. The above
if statement that increments the value of
$foo when the variable evaluates as true can be written as follows:
$foo++ if $foo == 7;
Clearly, using that reversed syntax can be an incredible saver of time and space when writing code. One must be aware of its rules and limitations, however. First of all, its elements are presented in an order opposite the usual method of representing the
if conditional and statement block, and secondly you can (in general: there are ways around this) only execute one expression if the control statement evaluates as true. The longer form of the standard
if statement allows for multiple instructions to be executed, while the shorter form only allows a single instruction to be executed.
unless, reversed
The same can be done with an
unless statement as with an
if statement. For instance, executing
$foo++ in the event that
$foo == 7 proves false would be represented by this
unless statement:
$foo++ unless $foo == 7;
&&/|| == if/unless reversed
An even shorter, simpler way to represent both of the above control structures exists:
$foo++ if $foo == 7;
is the same as
$foo == 7 && $foo++;
and
$foo++ unless $foo == 7;
is the same as
$foo == 7 || $foo++;
The reason these last variants on the
if and
unless statements work requires some understanding of formal logical constructions beyond that of the more traditional forms of conditionals. The
&& operator works as an
if conditional because of the manner in which it is applied by the interpreter:
- If $foo == 7 is true, then the value of the entire "and" expression is unknown. It cannot be evaluated as true or false as a whole until the part following the && operator is evaluated. The $foo++ portion is then executed and, because it's executed without fail, the complete expression $foo == 7 && $foo++; evaluates as true.
- If $foo == 7 is false, then the value of the second part of the entire statement ($foo++) is irrelevant because the whole statement can only be evaluated as true if both sides are true. The code for that expression stops before executing the increment operation.
Much the same occurs with the
unless statement using the
|| operator. I leave the details of this as an exercise for the reader.
Appendix A: operator precedence
It's worth noting that operator precedence is important in using the
&& and
|| operators to create
if and
unless statements. In general, anything of higher precedence than the
&& or
|| operator in your statement is safe to use in your
if statement or
unless statement. If a lower-precedence operator is used, it can cause parts of your expressions that make up (for instance) the control statement to be attached to a new expression involving the
&& or
|| operator, rather than being used as you intended.
All standard arithmetic operators and comparison operators are of higher precedence than
&& and
||. Assignment operators are lower precedence. The
and and
or operators perform precisely the same functions as
&& and
||, respectively, but have a much lower precedence. This lower precedence causes them to be executed after even assignment operators, commas, and list operators.
Much of this confusion over precedence can be avoided, of course, by simply using parentheses liberally (and properly). There are two somewhat contradictory schools of thought regarding the use of parentheses to CYA when dealing with operator precedence: one is that you should use parentheses often and with enthusiasm to ensure proper code execution, and the other is that you should always ensure that you know the proper operator precedence and avoid parentheses where possible. On one hand, it's true that diligent writing of code with avoidance of parentheses makes for a cleaner program and is, perhaps, a sign of some competence. On the other hand, using parentheses even where they might sometimes be avoided can aid in ease of parsing code by eye and maintaining code later. Ultimately, decisions on the matter must be made by the programmer.
Appendix B: more actions in one-line if statements
As I said in
if, reversed above, using one-line formats for the
if and
unless statement limits the programmer to only one executed statement when the control statement is evaluated as true (or, in the case of
unless, evaluated as false). I also said there are ways around it, though. I'll use
if, and not
unless, for my examples.
For one thing, even the standard format for an
if statement can be represented on one line. Thus,
if ($foo == 7){$foo++;} does the same thing as the following:
if ($foo == 7)
{
$foo++;
}
That's probably a bad idea, however. Using a statement block with braces around it allows for the flexibility of adding and subtracting statements within it, and collapsing it into one line renders the code less easy to read and maintain later without even making the code more succinct. The only keystrokes you really save involve your right pinky. The other methods of creating one-line
if statements I mentioned above are recommended where they're appropriate.
Another means of expanding the functionality of the one-line
if statement is to use the
and statement as described in
Appendix A above, which allows you to list multiple expressions for execution. For instance, you could do the following:
$foo == 7 and $foo++, $bar--;
You can also achieve much the same result through reliance on operator precendence. For instance, you could use this:
$foo == 7 && $foo++ && $bar++;
Other, innumerable exceptions apply to the one-line
if statement's limitations — far more than I can get into in this brief treatment of the subject.
Thanks due the PerlMonks community members who contributed suggestions and comments in discussion below.