-
Notifications
You must be signed in to change notification settings - Fork 0
PerlIntro2
In this lesson, we will look at control structures, subroutines, and modules. We are dealing with program flow!
“Control structures” here means ways to manipulate the program flow. Sometimes, a section of code should be repeated until a certain condition occurs, such as repeatedly reading a line of a file until the end of the file is reached. Or, as we have seen with lists, we may want to step through all the elements of a list. Or, a block of code should only be executed under very specific conditions. How these structures are used is best shown with examples.
my $x = 1;
while ($x) { # use $x as a boolean value
my $user_input = <STDIN>;
$x = ($user_input == 'quit');
}
my @list = qw ( itzy bitzy boo );
for (my $i=0; $i<@list; $i++) {
print $list[$i]."\n";
}
my @list = qw ( itzy bitzy boo );
foreach my $element (@list) {
print "$element\n";
}
if ($name eq 'boo') {
$foo = 'bar';
}
elsif ($name eq 'bitzy') {
$foo = 'batz'
}
else {
$foo = '';
}
Boolean algebra, applied to computer languages, refers to the fact that we can combine different conditions, and calculate the resulting true and false values. The most often operators are ‘or’, ‘and’ and ‘not’. For example, the operation true and true
is true
, whereas the operation true and false
is false
. The operation true or false
and false or true
or both true
, whereas false or false
is false
. true or true
is also true
. not false
is true, and not true
is false. Any questions?
As previously mentioned, Perl does not have, unlike other programming languages, a boolean type. Instead, the value of a scalar is interpreted in the following way: if the variable is undef, the empty string ''
or ""
, or a numeric value of zero, it is interpreted as false
. Any other value is true
. Most often, when a programmer needs to assign actual boolean values to a variable, 0
is used to represent false and 1
is used for true.
The operations are the following:
or
or ||
. Logical OR operator.
and
or &&
. Logical AND operator.
not
or !
. Logical NOT operator.
Note that in boolean algebra, the and
operator has precedence over or
. An expression such as ($a or $b and $c or $d)
may thus not yield the result you may have expected. Because and
has precedence over or
, in this example, $b and $c
is evaluated first. Then $a and the result of ($b and $c) is evaluated, and the or with $d is evaluated. This is similar the the mathematical operations, where multiplication has precedence over addition. (2 + 3 * 4 +5)
is 19, whereas ((2+3) * (4+5))
is 45. Similarly we can force the precedence of boolean operations with parentheses. If we meant (($a or $b) and ($c or $d))
we actually have to use the parentheses. Forgetting these parenthesis can yield to strange bugs! So be careful.
Example in Perl code. Note that Perl programmers usually prefer to use the &&
, ||
and !
versions of the operators.
if ($first_name eq 'itzy'
&& $last_name eq 'bitzy
|| $first_name eq 'batz'
&& $last_name eq 'boo') { # do something }
Note that Perl also has the bitwise or |
, and bitwise and &
operators. These are used to manipulate the bits of a scalar, not the Perl boolean values of the variable. For example, the binary value of $x = 255
would be 11111111
. A bitwise and with $y = 1
(bit representation 00000001) would yield 1.
Subroutines are pieces of code that are embedded in the larger program, and can be called by name with an optional list of parameters to perform some specific task. In Perl, subroutines can also return values.
Obviously, the task that a subroutine performs must be one that is needed in different parts of the program; instead of duplicating this code in the program, it is better to factor out a subroutine and call it from the different places in the program. In this manner, when bugs are found in the subroutine code, for example, the code needs to be fixed in only one place. This enhances the maintainability of the code.
In Perl, subroutines are defined by the keyword sub
, followed by a name, which must be unique in the program. Then follows the block { }
that contains the subroutine code, which can contain 0, one or several return statements. For example, a subroutine may be:
sub print_smiley {
print " :-) ";
}
We can now call the subroutine from anywhere in the program code we want, by just doing print_smiley();
, and it will always reliably print a :-)
. It really looks no different than a built in Perl function! We can therefore expand the language however we desire! Of course, our example is not very interesting. How can we feed parameters to the function and return values? For example, maybe we would like to do some calculation, such as the circumference of a rectangle. We would feed the width and the height of the rectangle as a parameters, do the calculation and return the result value. On the calling side, the parameters are simply a list provided to the calling function in the format calculate_circumference($width, $height)
. In the function, this parameter list appears in the exact calling order, in a special built-in list called @_
. We could therefore write:
sub calculate_circumference {
my ($width, $height) = @_;
my $circumference = 2 * ($width + $height);
return $circumference;
}
See also how we return the result value, using the aptly named ‘return’ statement.
We can retrieve the parameters in a slightly different way; remember the function shift
that removes the “left”-most element from a list?
Using shift, we could write:
sub calculate_circumference {
my $width = shift(@_);
my $height = shift(@_);
....
}
Conveniently, in a subroutine, the shift
operator operates on the special list @_
by default. Thus, we can write (and this is very popular with Perl programmers):
sub calculate_circumference {
my $width = shift;
my $height = shift;
.....
}
Note that Perl does not enforce the type of parameters as other languages, because of course it is not strongly typed to start with. There is a little used scheme to tell Perl how many parameters are being passed. Passing an incorrect number of parameters will lead to a compile error. The notation is:
sub calculate_circumference($$) {
my $width = shift;
my $height = shift;
....
}
However, this is rarely seen in any code. This was just mentioned for completeness. Please forget it now.
Imagine we have written a really useful subroutine. We use it extensively in our program, but now we have to write another program, where the subroutine would also be really useful. We could copy the subroutine into our new program, but now we have two copies of the subroutine (if we still use and maintain our old program) and bug fixes become complicated, because we have to fix them in two places.
In this situation, modules help. Modules can contain any number of subroutines, usually pertaining to some common problem.
Read the man page for Perl programming style, man perlstyle
.
Read the man page for the Perl operators, which talks about precedence, among other things man perlop
.
Read man perlpod
.