- Blocks
- The if Statement
- Looping
- Other Flow Control Tools
- Exercise: Finding Primes
- Summary
- Q&A
- Workshop
Other Flow Control Tools
Controlling the way your program executes with loops and condition statements is fine, but other flow control statements are needed to make readable programs. For example, Perl has statements to exit a while loop early, to skip certain portions of a for loop, to exit an if statement before the end of a block, or even to exit your program without falling off the end. Using some of the constructs explained in this section can make your Perl programs more concise and easier to read.
Odd Arrangements
The if statements have one more possible syntax. If you have only one expression inside the if block, the expression can actually precede the if statements. So, instead of writing
if (test_expression ) { expression ; }
you can write
expression if (test_expression );
The following are a couple of examples of this variation of the syntax:
$correct=1 if ($guess == $question); print "No pi for you!" if ( $ratio != 3.14159);
You usually use this syntax in Perl code for clarity; sometimes reading the code is easier if you see the action before the condition. The expression preceding the if must be a single expression. The if statement must also be followed by a semicolon.
Fine-Grained Control
In addition to blocks, for, while, if, and other flow-control statements that control blocks of code, you can use Perl statements to control the flow within the blocks.
The simplest statement that gives you this control is last. The last statement causes the innermost currently running loop block to be exited. Consider this example:
while($i<15) { last if ($i==5); $i++; }
The last statement causes the while loop to exit when the value of $i is 5, instead of normally when the while test is false. When you have multiple nested loop statements, last exits the loop currently running.
Listing 3.3 Example of the last Statement
1: for($i=0; $i<100; $i++) { 2: for($j=0; $j<100; $j++) { 3: if ($i * $j == 140) { 4: print "The product of $i and $j is 140\n"; 5: last; 6: } 7: } 8: }
The set of nested loops in Listing 3.3 finds all the whole numbers less than 100 whose products are 140—2 and 70, 4 and 35, and so on—rather inefficiently. The point to note here is the last statement. When a product is found, the result is printed, and the inner loop (the loop iterating over $j) is exited. The outer loop continues executing (by incrementing $i) and reruns the inner loop.
The next statement causes control to be passed back to the top of the loop and the next iteration of the loop to begin, if the loop isn’t finished:
for($i=0; $i<100; $i++) { next if (not $i % 2); print "An odd number=$i\n"; }
This loop prints all the even numbers from 0 to 98. The next statement causes the loop to go through its next iteration if $i is not even; the $i % 2 expression is the remainder of $i divided by 2. In this case, the print statement is skipped. (A much more efficient way to write this loop would be simply to increase $i by 2, but that wouldn’t demonstrate next, would it)?
The redo statement is similar to next, except that the condition isn’t re-evaluated. Perl resumes execution back at the beginning of the block and doesn’t check whether the termination condition has been met yet.
Labels
Perl allows blocks and some loop statements (for, while) to be labeled. That is, you can place an identifier in front of the block or statement:
MYBLOCK: { }
The preceding block is labeled as MYBLOCK. Label names follow the same conventions as variable names, with one small exception: Label names do not have an identifying character—%, $, @—as variables do. It’s important to make sure that label names do not clash with Perl’s built-in keywords. As a matter of style, it’s best if label names are all uppercase. You should not have any conflicts with any current or future Perl keywords that way. The for and while statements can all have labels as well.
OUTER: while($expr ) { INNER: while($expr) { statement; } }
The last, redo, and next statements can each take a label as an argument. You therefore can exit a specific block. The code in Listing 3.2 found two factors of 140 by using a nested pair of for loops. Suppose you wanted to exit the loops as soon as a factor is found. Without labels, you would need a complex arrangement of flag variables (variables whose only purpose is to store a true or false value for program flow control) and if statements between the two loops because you cannot exit the outer loop from within the inner loop. Labels solve this problem:
OUTER: for($i=0; $i<100; $i++) { for($j=0; $j<100; $j++) { if ($i * $j == 140) { print "The product of $i and $j is 140\n"; last OUTER; } } }
Now the last statement can specify which loop it wants to exit—in this case, the OUTER loop. This snippet prints only the first pair of factors of 140 that it finds.
Leaving Perl
The exit statement is the ultimate flow-control tool. When Perl encounters an exit statement, the program stops executing, and an exit status is returned by Perl to the operating system. This exit status is usually used to indicate successful completion of the program. You’ll learn more about exit statuses in Hour 11, "System Interaction." For now, an exit status of zero means everything went okay. The following is an example of exit:
if ($user_response eq ‘quit’) { print "Good Bye!\n"; exit 0; # Exit with a status of 0. }