EIW Fall 2004 Lecture Notes

Perl Control Structures


if   unless   while   until   for   foreach  

Control Structures

Control Structures provide a means of controlling the flow of a program. So far we've looked only at basic expressions, now we look at how to tie these expressions together in to a program that can iterate (loop) or make decisions (conditionals) based on the state of variables.

Perl contains the typical assortment of control structures including if-then-else conditionals, while and for loops. Perl also contains some new control structures you may not have seen before (new to a C/C++ programmer).

The if statement

The perl if statement looks much like a C if statement. Here is the general structure:

if (expression) {
	stmt1;
}

The value of expression determines whether or not the perl statement stmt1 is executed. If the value of expression is considered "TRUE" by perl, then stmt1 is executed, otherwise stmt1 is skipped.

perl TRUE and FALSE

In the C language any non-zero value is considered to be TRUE and the value 0 is considered FALSE. In perl things are a bit more complex, this is necessary since we often deal with strings (not just numbers). In perl, the following determine the TRUTH of an expression:

*: There is an exception to this rule - the string "0" is FALSE

Formally, perl first converts a conditional value to a string and then if the result is either the empty string or the string "0" the expression is FALSE, otherwise it is TRUE. Note that the string "00" is considered TRUE!

The special perl value undef is considered false (formally this is because when converted to a string it has the value "").

Curly Brackets

In perl you can create a block of statements by enclosing a sequence of statements inside curly braces { }. In C/C++ a single statment inside a control strucuture (like an IF) does not require curly braces - in perl the curly braces are always required.

If Examples

We can now look at some example if statements:

# prompt and read in a value from stdin
printf("Enter a number greater than 0\n");
$num = <STDIN>;

# make sure they followed the directions
if ($num < 1) {
  print "Not a valid number dummy!\n";
}

# if the number is less than 50, call user a pessimist
if ($num < 50) {
  print "Your number is too small, you must not be a happy person\n";
}

Perl allows a sequence of statements inside the curly braces, this sequence can include multiple if statements (any kind of statement). Perl also supports an else continuation of the if. A more complex example:

# prompt and read in a value from stdin
printf("Enter a number between 1 and 100 inclusive\n");
$num = <STDIN>;

# make sure they followed the directions
if ($num >= 1) {
    if ($num <= 100) {

	# They followed directions - now evaluate thier personality
	if ($num < 50) {
	    print "Your number is small - you think little of yourself\n";
	} else {
	    print "Your number is large - you think too much of yourself\n";
	}
    } else {
	# they entered a number too large - call them a name
	print "Your number is too large dummy!\n";
    }
} else {
    # the number entered is too small - call them a name
    print "Your number is too small you are either a zero or too negative!\n";
}

A common pattern is a sequence of if-else statements. In perl you can combine an else with a following if with an elsif as in this example:

print "Enter a number between 1 and 100 inclusive\n";
$num = <STDIN>;

# 1-33 is too small
# 34-65 is just right
# 66-100 is too big

if ($num < 1) {
    print "Invalid\n";
} elsif ($num < 34) {
    print "Too small\n";
} elsif ($num < 66) {
    print "Just right\n";
} elsif ($num < 101) {
    print "Too large\n";
} else {
    print "Invalid\n";
}

The unless Control Structure

Ever want to leave off the if part and just keep the else part of an if-else? Perl has just what you need - it's called unless. The statments inside an unless are not executed if the conditional expression is TRUE:


# we could do it this way

if ($cookie{$student} eq "chocolatechip") {
    # do nothing - this student is OK
} else {
    print "You fail!\n";
}

# or we could use an unless

unless ($cookie{$student} eq "chocolatechip") {
   print "You fail!\n";
}

The while statement

A perl while is used to create iteration (loops). The general form looks like this:

while (expression) {
   stmt1;
   ...   # could be more statments here
}

This is like an if except that stmt1 (and any others inside the braces) is executed over and over as long as expression is TRUE.

print "Enter a number greater than 0\n";
$num = <STDIN>;

$tries = 1;

# keep doing until the user gets it right!

while ($num <= 0) {
    print "Tough day? (try again)\n";
    print "Enter a number greater than 0\n";
    $num = <STDIN>;

    # keep track of how many times it takes to get it right
    $tries = $tries + 1;
}

print "You did that in $tries tries\n";

The until loop

If you would prefer to have the statements inside the loop repeated until some condition is FALSE, you can use an until:

print "Enter a number greater than 0\n";
$num = <STDIN>;

$tries = 1;

# keep doing until the user gets it right!

until ($num > 0) {
    print "Tough day? (try again)\n";
    print "Enter a number greater than 0\n";
    $num = <STDIN>;

    # keep track of how many times it takes to get it right
    $tries = $tries + 1;
}

print "You did that in $tries tries\n";

Looping over input

Perl programs often execute a sequence of statements for each line of input read in. The <STDIN> input operator returns the next line of input available each time it is called, and returns the special perl value undef when the end of file has been found. We can use <STDIN> as the condition used to control a loop:

# read in lines from stdin one at a time, and print them back out.

while ($line = <STDIN>) {
    print $line;
}

# This code simply prints out whatever it gets from STDIN

Logical Operators - OR and AND

Perl supports C style logical operators that can be used to build complex conditionals. The || operator is a binary operator that is TRUE if either operand is TRUE. So the expression ( $num < 0 ) || ( $num > 100) is true if either $num < 0 or if $num > 100. Perl also supports the && operator (logical AND) that is true only when both operands are true. Some examples:

print "Enter a number between 1 and 100 inclusive\n";
$num = <STDIN;>;

# if num is less than 1 or greater than 100 - not valid input.

if ( ( $num < 1) || ( $num > 100 ) ) {
    print "Dummy - can't you follow directions!?!\n";
} else {
    print "Excellent - you would make a great physican\n";
}

# if num is between 33 and 66 this is a great user!

if ( ($num>33) && ($num<66) ) {
    print "You are quite a user, best I've seen today!\n";
}

The for loop

Perl supports a for loop that looks just like C:

for ( initializer ; expression ; increment ) {
    stmt1;
    ...   # could be more statements here
}

The loop works like this:

  1. The initializer statement is executed. This typically initializes some variable or variables that are tested in the expression.
  2. The expression is evaluated and if it is TRUE, stmt1 (and any others inside the braces) are executed. If expression is FALSE the loop is done - go to step 5.
  3. After executing stmt1 the increment statement is executed. This typically modifies some variable that is tested in expression.
  4. after increment is executed go back to step 2.
  5. loop is done.

Here is a real example that prints out the numbers from 1 to 10:

for ($i=1 ; $i <= 10 ; $i = $i+1 ) {
  print "$i\n";
}

Here the initializer sets $i to have the value 1. Then the expression $i <= 10 is evaluated and found to be TRUE ($i is still 1). Since the expression is TRUE, the print statement is executed. Next the increment statement is executed, this simply adds one to $i, so now $i has the value 2. The loop now goes back to the expression, $i is still less than 10 so the loop continues.

Once $i gets the value 11, the expression will no longer be TRUE and the loop will terminate.

It is often useful to realize that the initializer and increment statments can do anything at all! Here is another example:


# print out a list of names, one per line

for ( @names = ("Bill","Mary","John","Sue") ;  @names != 0 ;  shift( @names ) {
   print "Name is $names[0]\n";
}

The foreach statement

The perl foreach is another iteration control structure. A scalar variable takes on each of the values from an array before a block of statements is executed. Here is the general structure:

foreach $var (@an_array) {
    stmt1;
    ...    # could be more statements here
}

The first time the body of the loop is executed the variable $var has the value $an_array[0], the next time it has the value $an_array[1] and so on through the array. An example:

# define an array
@names = ("Bill", "Nancy", "John", "Susan");

# print out each name on it's own line
foreach $i (@names) {
    print "Name is $i\n";
}
# This code should output:
#   Name is Bill
#   Name is Nancy
#   Name is John
#   Name is Susan

A foreach doesn't need to have $var specified, so it can look like this:

foreach (@an_array) {
    stmt1;
    ...    # could be more statements here
}

If no scalar variable is present in a foreach then perl uses the default scalar variable $_. The example could now become:

# define an array
@names = ("Bill", "Nancy", "John", "Susan");

# print out each name on it's own line
foreach (@names) {
    print "Name is $_\n";
}

The default scalar variable $_ has lots of uses in perl - many operators will use this scalar variable when no other variable is specified. For example, the print operator will default to printing the value of $_ if nothing else is specified. We can use this to again change our foreach example:

# define an array
@names = ("Bill", "Nancy", "John", "Susan");

# print out each name on it's own line
foreach $i (@names) {
    print;
}
# This code should output:
#   BillNancyJohnSusan

foreach and array modifications

If the array specified in a foreach statement is an array variable (not a constant or an array produced by an expression) then any changes made to the scalar variable $var are reflected in the array. An example might help make this clear:

# define an array
@nums = (1..5);      # @nums is (1, 2, 3, 4, 5)

# double each array element
foreach $i (@nums) {
	$i = $i * 2;
}

# now @nums is (2, 4, 6, 8, 10)