If you look at a Perl program from a very high level, it is made of statements. Statements are a complete unit of instruction for the computer to process. The computer executes each statement it sees-in sequence-until a jump or branch is processed.
Statements can be very simple or very complex. The simplest statement is this
123;
which is a numeric literal followed by a semicolon. The semicolon is very important. It tells Perl that the statement is complete. A more complicated statement might be
$bookSize = ($numOfPages >= 1200 ? "Large" : "Normal");
which says if the number of pages is 1,200 or greater, then assign "Large" to $bookSize; otherwise, assign "Normal" to $bookSize.
In Perl, every statement has a value. In the first example, the value of the statement is 123. In the second example, the value of the statement could be either "Large" or "Normal" depending on the value of $numOfPages. The last value that is evaluated becomes the value for the statement.
Like human language in which you put statements together from parts of speech-nouns, verbs, and modifiers-you can also break down Perl statements into parts. The parts are the literals, variables, and functions you have already seen in the earlier chapters of this book.
Human language phrases-like, "walk the dog"-also have their counterparts in computer languages. The computer equivalent is an expression. Expressions are a sequence of literals, variables, and functions connected by one or more operators that evaluate to a single value-scalar or array. An expression can be promoted to a statement by adding a semicolon. This was done for the first example earlier. Simply adding a semicolon to the literal made it into a statement that Perl could execute.
Expressions may have side effects, also. Functions that are called can do things that are not immediately obvious (like setting global variables) or the pre- and post-increment operators can be used to change a variable's value.
Let's take a short diversion from our main discussion about statements and look at expressions in isolation. Then we'll return to statements to talk about statement blocks and statement modifiers.
You can break the universe of expressions up into four types:
Simple expressions consist of a single literal or variable.
Table 6.1 shows some examples. Not much can be said about these
expressions because they are so basic. It might be a matter for
some debate whether or not an array or associative array variable
can be considered a simple expression. My vote is yes, they can.
The confusion might arise because of the notation used to describe
an array or associative array. For example, an array can be specified
as (12, 13, 14). You can
see this specification as three literal values surrounded by parentheses
or one array. I choose to see one array which fits the definition
of a simple expression-a single variable.
Simple Expression | Description |
123 | Integer literal |
Chocolate is great! | String literal |
(1, 2, 3) | Array literal |
$numPages | Variable |
Simple expressions with side effects are the next type
of expression we'll examine. A side effect is when a variable's
value is changed by the expression. Side effects can be caused
using any of the unary operators: +,
-, ++, --. These operators
have the effect of changing the value of a variable just by the
evaluation of the expression.No other Perl operators have this
effect-other than the assignment operators, of course. Function
calls can also have side effects- especially if local variables
were not used and changes were made to global variables. Table
6.2 shows examples of different side effects.
Simple Expression | Description |
$numPages++ | Increments a variable |
++$numPages | Increments a variable |
chop($firstVar) | Changes the value of $firstVar-a global variable |
sub firstsub { $firstVar = 10; } | Also changes $firstVar |
Note that when the expressions $numPages++ and ++$numPages are evaluated, they have the same side effect even though they evaluate to different values. The first evaluates to $numPages, and the second evaluates to $numPages + 1. The side effect is to increment $numPages by 1.
The firstsub() function shown in Table 6.2 changes the value of the $firstVar variable, which has a global scope. This can also be considered a side effect, especially if $firstVar should have been declared as a local variable.
Simple expressions with operators are expressions that
include one operator and two operands. Any of Perl's binary operators
can be used in this type of expression. Table 6.3 shows a few
examples of this type of expression.
Simple Expression | Description |
10 + $firstVar | Adds ten to $firstVar |
$firstVar . "AAA" | Concatenates $firstVar and "AAA" |
"ABC" x 5 | Repeats "ABC" five times |
Another way of viewing 10 + $firstVar is as simple expression plus simple expression. Thus, you can say that a simple expression with an operator is defined as two simple expressions connected by an operator. When computer programmers define something in terms of itself, we call it recursion. Each time a recursion is done, the expression is broken down into simpler and simpler pieces until the computer can evaluate the pieces properly.
A complex expression can use any number of literals, variables,
operators, and functions in any sequence. Table 6.4 shows some
complex expressions.
Complex Expression |
(10 + 2) + 20 / (5 ** 2) |
There is an infinite number of expressions you can form with the
Perl operator set. You can get extremely complicated in your use
of operators and functions if you are not careful. I prefer to
keep the expressions short, easy to document, and easy to maintain.
Tip |
Sometimes it is difficult to tell whether you have enough closing parentheses for all of your opening parentheses. Starting at the left, count each open parenthesis, and when you find a closing parenthesis, subtract one from the total. If you reach zero at the end of the expression, the parentheses are balanced. |
Now we'll go back to looking at statements.
A statement block is a group of statements surrounded by curly braces. Perl views a statement block as one statement. The last statement executed becomes the value of the statement block. This means that any place you can use a single statement-like the map function-you can use a statement block. You can also create variables that are local to a statement block. So, without going to the trouble of creating a function, you can still isolate one bit of code from another.
Here is how I frequently use a statement block:
$firstVar = 10; { $secondVar >>= 2; $secondVar++; } $thirdVar = 20;
The statement block serves to emphasize that the inner code is set apart from the rest of the program. In this case, the initialization of $secondVar is a bit more complex than the other variables. Using a statement block does not change the program execution in any way; it simply is a visual device to mark sections of code and a way to create local variables.
Normally, it's a good idea to place all of your variable initialization at the top of a program or function. However, if you are maintaining some existing code, you may want to use a statement block and local variables to minimize the impact of your changes on the rest of the code-especially if you have just been handed responsibility for a program that someone else has written.
You can use the my() function to create variables whose scope is limited to the statement block. This technique is very useful for temporary variables that won't be needed elsewhere in your program. For example, you might have a complex statement that you'd like to break into smaller ones so that it's more understandable. Or you might want to insert some print statements to help debug a piece of code and need some temporary variables to accommodate the print statement.
Assign ten to $firstVar.
Start the statement block.
Create a local version of $firstVar with a value of A.
Print $firstVar repeated five times.
End the statement block.
Print the global $firstVar.
$firstVar = 10; { my($firstVar) = "A"; print $firstVar x 5 . "\n"; } print("firstVar = $firstVar\n");
This program displays:
AAAAA firstVar = 10
You can see that the value of $firstVar
has been unchanged by the statement block even though a variable
called $firstVar is used
inside it. This shows that the variable used inside the statement
block does indeed have a local scope.
Tip |
Statement blocks are also good to use when you temporarily need to send debugging output to a file. Then, when all the bugs have been found and the need for debugging is over, you can remove the statement block quickly and easily because all the code is in one spot. |
Just as there were several types of expressions, there are also
several types of statements. Table 6.5 lists seven different types
of statements.
Statement Type | Description |
No-action statements | These statements evaluate a value but perform no actions. |
Action statements | These statements perform some action. |
Assignment statements | These statements assign a value to one or more variables. They are discussed, along with the assignment operator, in Chapter 4 "Operators." |
Decision statements | These statements allow you to test a condition and choose among one or more actions. Decision statements are discussed in Chapter 7 "Control Statements." |
Jump statements | These statements let you unconditionally change the program flow to another point in your code. For instance, you could use the redo keyword to send your program flow back to the beginning of a statement block. Jump statements are discussed in Chapter 7 "Control Statements." |
Loop statements | These statements let you perform a series of statements repeatedly while some condition is true or until some condition is true. Loop statements are discussed in Chapter 7 "Control Statements." |
Modified Statements | These statements let you use the if, unless, until, and while keywords to change the behavior of a statement. |
Note |
A keyword is a word that is reserved for use by Perl. These words (if, elsif, else, while, unless, until, for, foreach, last, next, redo, and continue) are integral to the language and provide you with the ability to control program flow. |
No-action statements are evaluated by Perl and have a value but perform no actions. For instance, the Perl statement 10 + 20; has a value of 30, but because no variables were changed, no work was done. The value of 20 is not stored anywhere, and it is quickly forgotten when the next statement is seen.
What good is a no-action statement if no work is done? A lot of Perl programmers use these simple statements as return values in functions. For instance:
sub firstSub { doSomething(); condition == true ? "Success" : "Failure"; }
Because Perl returns the value of the last evaluated statement
when leaving a function, you can use no-action statements to let
Perl know what value should be returned to the main program. Notice
that even though the ternary operator was used, because there
are no function calls or unary operators, no work can be done.
Note |
I still like to use the return() function to explicitly identify the return values. The previous example looks like this when using the return() function: |
sub firstSub { doSomething(); return(condition == true ? "Success" : "Failure"); }
Action statements use expressions to perform some task. They can increment or decrement a variable and call a function.
Modified statements use expressions in conjunction with a modifying keyword to perform some action. There are four modifying keywords: if, unless, until, and while. The basic syntax of a modified statement is
EXPRESSION modifier (CONDITION);
Let's look at some examples of modified statements.
The if modifier tells Perl that the expression should be evaluated only if a given condition is true. The basic syntax of a modified statement with the if modifier is
EXPRESSION if (CONDITION);
This is a compact way of saying
if (CONDITION) { EXPRESSION; }
Let's prove that the if modifier works. Here's an example showing that the if modifier can prevent the evaluation of an expression.
Initialize the $firstVar and $secondVar variables to 20.
Increment $firstVar if and only if $secondVar is equal to 10.
Print the values of $firstVar and $secondVar.
$firstVar = 20; $secondVar = 20; $firstVar++ if ($secondVar == 10); print("firstVar = $firstVar\n"); print("secondVar = $secondVar\n");
This program prints:
firstVar = 20 secondVar = 20
The program doesn't increment $firstVar because the value of $secondVar is 20 at the time the condition is evaluated. If you changed the 10 to a 20 in the condition, Perl would increment $firstVar.
You can find out about the if
statement-as opposed to the if
modifier-in Chapter 7 "Control Statements."
Note |
The condition expression can be as complex as you'd like. However, I believe that one of the goals of statement modifiers is to make programs easier to read and understand. Therefore, I use modifiers only with simple conditions. If complex conditions need to be met before an expression should be evaluated, using the if keyword is probably a better idea. |
The unless modifier is the opposite of the if modifier. This modifier evaluates an expression unless a condition is true. The basic syntax of a modified statement with the unless modifier is
EXPRESSION unless (CONDITION);
This is a compact way of saying
if (! CONDITION) { EXPRESSION; }
This modifier helps to keep program code clearly understandable because you don't have to use the logical not operator to change the value of a condition so you can evaluate an expression. Let's look back at the example from a moment ago.
Initialize the $firstVar and $secondVar variables to 20.
Increment $firstVar unless $secondVar is equal to 10.
Print the values of $firstVar and $secondVar.
$firstVar = 20; $secondVar = 20; $firstVar++ unless ($secondVar == 10); print("firstVar = $firstVar\n"); print("secondVar = $secondVar\n");
This program prints:
firstVar = 21 secondVar = 20
If you were limited to using only the if modifier, the modified statement would read
$firstVar++ if ($secondVar != 10);
The unless modifier is more direct. All things being equal, the concept of $secondVar being equal to 10 is easier to grasp than the concept of $secondVar not being equal to 10. Of course, this is a trivial example. Let's look at something more substantial before we move on.
One of the drawbacks of associative arrays is that they quietly redefine the value of any key when that key is assigned a new value, thereby losing the old value. If you are reading from a list of key-value pairs, this might not be the behavior you need. The unless modifier can be used to prevent element assignment if the key has already been used. Listing 6.1 shows the unless modifier used in a program.
Call the assignElement() function to create two elements in the @array associative array.
Call the printArray() function.
Try to redefine the value associated with the "A" key by calling assignElement().
Print the array again to verify that no elements have changed.
Listing 6.1 06LST01.PL-Using the unless Modifier to Control Array Element Assignment
assignElement("A", "AAAA"); assignElement("B", "BBBB"); printArray(); assignElement("A", "ZZZZ"); printArray(); sub assignElement { my($key, $value) = @_; $array{$key} = $value unless defined($array{$key}); } sub printArray { while (($key, $value) = each(%array)) { print("$key = $value\n"); } print("\n"); }
This program displays:
A = AAAA B = BBBB A = AAAA B = BBBB
These lines of code should look a little familiar to you. The while loop in the printArray() function was used in a Chapter 5example. The assignElement() function will make an assignment unless a key-value pair with the same key already exists. In that case, the assignment statement is bypassed.
The until modifier is a little more complex than the if or unless modifiers. It repeatedly evaluates the expression until the condition becomes true. The basic syntax of a modified statement with the until modifier is
EXPRESSION until (CONDITION);
This is a compact way of saying
until (CONDITION) { EXPRESSION; }
The expression is evaluated only while the condition is false. If the condition is true when the statement is encountered, the expression will never be evaluated. The following example proves this:
Initialize $firstVar to 10.
Repeatedly evaluate $firstVar++ until the condition $firstVar > 2 is true.
Print the value of $firstVar.
$firstVar = 10; $firstVar++ until ($firstVar > 2); print("firstVar = $firstVar\n");
This program displays:
firstVar = 10
This shows that the expression $firstVar++ was never executed because the condition was true the first time it was evaluated. If it had been executed, the value of $firstVar would have been 11 when printed. In this case, the until modifier worked exactly like the unless modifier.
However, when the condition is false for the first evaluation, Perl executes the expression repeatedly until the condition is true. Here is an example:
Initialize $firstVar to 10.
Repeatedly evaluate $firstVar++ until the condition $firstVar > 20 is true.
Print the value of $firstVar.
$firstVar = 10; $firstVar++ until ($firstVar > 20); print("firstVar = $firstVar\n");
This program displays:
firstVar = 21
In this case, the $firstVar++ expression is executed 11 times. Each execution of the expression increments the value of $firstVar. When $firstVar is equal to 21, the statement ends because 21 is greater than 20, which means that the condition is true.
You can find out about the until statement-as opposed to the until modifier-in Chapter 7 "Control Statements."
The while modifier is the opposite of the until modifier. It repeatedly evaluates the expression while the condition is true. When the condition becomes false, the statement ends. The basic syntax of a modified statement with the while modifier is
EXPRESSION while (CONDITION);
This is a compact way of saying
while (CONDITION) { EXPRESSION; }
The expression is evaluated only while the condition is true. If the condition is false when the statement is encountered, the expression will never be evaluated. Here is an example using the while modifier.
Initialize $firstVar to 10.
Repeatedly evaluate $firstVar++ while the condition $firstVar < 20 is true.
Print the value of $firstVar.
$firstVar = 10; $firstVar++ while ($firstVar < 20); print("firstVar = $firstVar\n");
This program displays:
firstVar = 21
You can compare this example directly to the last example given for the until modifier. Because the until modifier is the opposite of the while modifier, the operators in the conditions are also opposite in nature.
You can find out about the while statement-as opposed to the while modifier-in Chapter 7 "Control Statements."
This chapter discussed Perl statements and how they are built from expressions. You read about four types of expressions: simple, simple with side effects, simple with operators, and complex.
Next, you read about statement blocks. These program constructs are good to logically isolate one block of statements from the main program flow. You can also use statement blocks and the my() function to create local variables. This is mainly done for debugging reasons or to make small program changes that are guaranteed not to affect other portions of the program.
Then, seven types of statements were mentioned: no-action, action, assignment, decision, jump, loop, and modified. This chapter described no-action, action, and modified statements. Assignment statements were mentioned in Chapter 3"Variables" and again in Chapter 4 "Operators." Decision, jump, and loop statements are covered in Chapter 7 "Control Statements."
Modified statements use the if, unless, until, and while keywords to affect the evaluation of an expression. The if keyword evaluates an expression if a given condition is true. The unless keyword does the opposite: the expression is evaluated if a given condition is false. The until keyword repeatedly evaluates an expression until the condition is true. The while keyword is the opposite of until so that it repeatedly evaluates an expression until the condition is false.
The next chapter, "Control Statements," explores the decision, jump, and loop statements in detail.
Answers to Review Questions are in Appendix A.
$firstVar = 10; $secondVar = 20; $firstVar += $secondVar++ if ($firstVar > 10); print("firstVar = $firstVar\n"); print("firstVar = $secondVar\n");