< BACKCONTINUE >

5.1 Flow Control

Flow control is the order in which the statements of a program are executed. A program executes from the first statement at the top of the program to the last statement at the bottom, in order, unless told to do otherwise. There are two ways to tell a program to do otherwise: conditional statements and loops. A conditional statement executes a group of statements only if the conditional test succeeds; otherwise, it just skips the group of statements. A loop repeats a group of statements until an associated test fails.

5.1.1 Conditional Statements

Let's take another look at the open statement. Recall that if you try to open a nonexistent file, you get error messages. You can test for the existence of a file explicitly, before trying to open it. In fact, such tests are among the most powerful features of computer languages. The if , if-else, and unless conditional statements are three such testing mechanisms in Perl.

The main feature of these kinds of constructs is the testing for a conditional. A conditional evaluates to a true or false value. If the conditional is true, the statements following are executed; if the conditional is false, they are skipped (or vice versa).

However, "What is truth?" It's a question that programming languages may answer in slightly different ways.

This section contains a few examples that demonstrate some of Perl's conditionals. The true-false condition in each example is equality between two numbers. Notice that equality of numbers is represented by two equal signs ==, because the single equal sign = is already used for assignment to a variable.

Confusion between = for assignment and == for numeric equality is a frequent programming bug, so watch for it!

The following examples demonstrate whether the conditional will evaluate to true or false. You don't ordinarily have much use for such simple tests. Usually you test the values that have been read into variables or the return value of function calls—things you don't necessarily know beforehand.

The if statement with a true conditional:

if( 1 == 1) {

    print "1 equals 1\n\n";
}

produces the output:

1 equals 1

The test is 1 == 1, or, in English, "Does 1 equal 1?" Since it does, the conditional evaluates to true, the statement associated with the if statement is executed, and a message is printed out.

You can also just say:

if( 1) {
    print "1 evaluates to true\n\n";
}

which produces the output:

1 evaluates to true

The if statement with a false conditional:

if( 1 == 0) {
    print "1 equals 0\n\n";
}

produces no output! The test is 1 == 0 or, in English, "Does 1 equal 0?" Since it doesn't, the conditional evaluates to false, the statements associated with the if statement aren't executed, and no message is printed out.

You can also just say:

if( 0 ) {
    print "0 evaluates to true\n\n";
}

which produces no output, since 0 evaluates to false, so the statements associated with the if statement are skipped entirely.

There's another way to write short if statements that mirrors how the English language works. In English, you can say, equivalently, "If you build it, they will come" or "They will come if you build it." Not to be outdone, Perl also allows you to put the if after the action:

print "1 equals 1\n\n" if (1 == 1);

which does the same thing as the first example in this section and prints out:

1 equals 1

Now, let's look at an if-else statement with a true conditional:

if( 1 == 1) {
    print "1 equals 1\n\n";
} else {
    print "1 does not equal 1\n\n";
}

which produces the output:

1 equals 1

The if-else does one thing if the test evaluates to true and another if the test evaluates to false. Here is if-else with a false conditional:

if( 1 == 0) {
    print "1 equals 0\n\n";
} else {
    print "1 does not equal 0\n\n";
}

which produces the output:

1 does not equal 0

The final example is unless—the opposite of if. It works like the English word "unless": e.g., "Unless you study Russian literature, you are ignorant of Chekov." If the conditional evaluates to true, no action is taken; if it evaluates to false, the associated statements are executed. If "you study Russian literature" is false, "you are ignorant of Chekov."

unless( 1 == 0) {
    print "1 does not equal 0\n\n";
}

produces the output:

1 does not equal 0
5.1.1.1 Conditional tests and matching braces

Two more comments are in order about these statements and their conditional tests.

First, there are several tests that can be used in the conditional part of these statements. In addition to numeric equality == as in the previous example, you can also test for inequality !=, greater than >, less than <, and more.

Similarly, you can test for string equality using the eq operator: if two strings are the same, it's true. There are also file test operators that allow you to test if a file exists, is empty, if permissions are set a certain way, and so on (see Appendix B). One common test is just a variable name: if the variable contains zero, it's considered false; any other number evaluates to true. If the variable contains a nonempty string, it evaluates to true; the empty string, designated by "" or '', is false.

Second, notice that the statements that follow the conditional are enclosed within a matching pair of curly braces. These statements within curly braces are called a block and arise frequently in Perl.[1] Matching pairs of parentheses, brackets, or braces, i.e., ( ), [ ], < >, and { }, are common programming features. Having the same number of left and right braces in the right places is essential for a Perl program to run correctly.

[1] As something of an oddity, the last statement within a block doesn't need a semicolon after it.

Matching braces are easy to lose track of, so don't be surprised if you miss some and get error messages when you try to run the program. This is a common syntax error; you have to go back and find the missing brace. As code gets more complex, it can be a challenge to figure out where the matching braces are wrong and how to fix them. Even if the braces are in the right place, it can be hard to figure out what statements are grouped together when you're reading code. You can avoid this problem by writing code that doesn't try to do too much on any one line and uses indentation to further highlight the blocks of code (see Section 5.2).[2]

[2] Some text editors help you find a matching brace (for instance, in the vi editor, hitting the percent key % over a parenthesis bounces you to the matching parenthesis).

Back to the conditional statements. The if-else also has an if-elsif-else form, as in Example 5-1. The conditionals, first the if and then the elsifs, are evaluated in turn, and as soon as one evaluates to true, its block is executed, and the rest of the conditionals are ignored. If none of the conditionals evaluates to true, the else block is executed if there is one—it's optional.

Example 5-1. if-elsif-else
#!/usr/bin/perl -w
# if-elsif-else

$word = 'MNIDDKL';

# if-elsif-else conditionals
if($word eq 'QSTVSGE') {

    print "QSTVSGE\n";

} elsif($word eq 'MRQQDMISHDEL') {

    print "MRQQDMISHDEL\n";

} elsif ( $word eq 'MNIDDKL' ) {

    print "MNIDDKL--the magic word!\n";

} else {

    print "Is \"$word\" a peptide? This program is not sure.\n";

}

exit;

Notice the \" in the else block's print statement; it lets you print a double-quote sign (") within a double-quoted string. The backslash character tells Perl to treat the following " as the sign itself and not interpret it as the marker for the end of the string. Also note the use of eq to check for equality between strings.

Example 5-1 gives the output:

MNIDDKL--the magic word!

5.1.2 Loops

A loop allows you to repeatedly execute a block of statements enclosed within matching curly braces. There are several ways to loop in Perl: while loops, for loops, foreach loops, and more. Example 5-2 (from Chapter 4) displays the while loop and how it's used while reading protein sequence data in from a file.

Example 5-2. Reading protein sequence data from a file, take 4
#!/usr/bin/perl -w
# Reading protein sequence data from a file, take 4

# The filename of the file containing the protein sequence data
$proteinfilename = 'NM_021964fragment.pep';

# First we have to "open" the file, and in case the
# open fails, print an error message and exit the program.
unless ( open(PROTEINFILE, $proteinfilename) ) {

    print "Could not open file $proteinfilename!\n";
    exit;
}

# Read the protein sequence data from the file in a "while" loop,
# printing each line as it is read.
while( $protein = <PROTEINFILE> ) {

    print "  ######  Here is the next line of the file:\n";

    print $protein;
}

# Close the file.
close PROTEINFILE;

exit;

Here's the output of Example 5-2:

  ######  Here is the next line of the file:
MNIDDKLEGLFLKCGGIDEMQSSRTMVVMGGVSGQSTVSGELQD
  ######  Here is the next line of the file:
SVLQDRSMPHQEILAADEVLQESEMRQQDMISHDELMVHEETVKNDEEQMETHERLPQ
  ######  Here is the next line of the file:
GLQYALNVPISVKQEITFTDVSEQLMRDKKQIR

In the while loop, notice how the variable $protein is assigned each time through the loop to the next line of the file. In Perl, an assignment returns the value of the assignment. Here, the test is whether the assignment succeeds in reading another line. If there is another line to read in, the assignment occurs, the conditional is true, the new line is stored in the variable $protein, and the block with the two print statements is executed. If there are no more lines, the assignment is undefined, the conditional is false, and the program skips the block with the two print statements, quits the while loop, and continues to the following parts of the program (in this case, the close and exit functions).

5.1.2.1 open and unless

The open call is a system call, because to open a file, Perl must ask for the file from the operating system. The operating system may be a version of Unix or Linux, a Microsoft Windows versions, one of the Apple Macintosh operating systems, and so on. Files are managed by the operating system and can be accessed only by it.

It's a good habit to check for the success or failure of system calls, especially when opening files. If a system call fails, and you're not checking for it, your program will continue, perhaps attempting to read or write to a file you couldn't open in the first place. You should always check for failure and let the user of the program know right away when a file can't be opened. Often you may want to exit the program on failure or try to open a different file.

In Example 5-2, the open system call is part of the test of the unless conditional.

unless is the opposite of if. Just as in English you can say "do the statements in the block if the condition is true"; you can also say the opposite, "do the statements in the block unless the condition is true." The open system call gives you a true value if it successfully opens the file; so here, in the conditional test of the unless statement, if the open call fails, the statements in the block are performed, the program prints an error message, and then exits.

To sum up, conditionals and loops are simple ideas and not difficult to learn in Perl. They are among the most powerful features of programming languages. Conditionals allow you to tailor a program to several alternatives, and in that way, make decisions based on the type of input it gets. They are responsible for a large part of whatever artificial intelligence there is in a computer program. Loops harness the speed of the computer so that in a few lines of code, you can handle large amounts of input or continually iterate and refine a computation.

< BACKCONTINUE >

Index terms contained in this section

! (bang)
      != (not equal to) operator
" (quotes, double)
      within double-quoted strings
(angle brackets)
     > (right angle bracket)
            greater than operator
     < (left angle bracket)
            less than operator
= (equal sign)
      == (equal to) operator
      assignment operator
\\\\ (backslash)
      escaping quotes within quoted strings
{} (curly braces)
      for statement blocks
backslash (\\\\)
blocks
close function
conditional statements
exit function
false or true value, evaluating with conditionals
files
     opening
            with system calls
flow control
      conditional statements
      loops
for loops
foreach loops
greater than (>)
if statements
if-else statements
      example
if-elsif-else statements
inequality, testing for
less than (<)
loops 2nd
numeric equality (==), testing for
open system call
opening files
      testing for file existence before attempting
operating systems
      opening files on
operators
     assignment
            equality vs.
Perl
      conditional statements
      loops
proteins
     sequences
            reading from file with while loop
reading
      protein sequence data from a file, using while loop
sequences
     protein
            reading from file with while loop
statements
      block
      flow control
system calls
      checking success or failure of
      open, using with unless statement
text editors
      missing braces, locating
true or false value, evaluating with conditionals
unless statements 2nd
      example
while loops

© 2002, O'Reilly & Associates, Inc.