Main

March 17, 2004 (Wednesday)

Scalars (S&P — Chapter 2, cont'd)

Pre/Post Increment/Decrement

As with C and C++, Perl supports post/pre-increment/decrement operators that behave in much the same way. Unlike C and C++, we can apply these operators to strings as well as numbers:

#!/usr/bin/perl -w

use strict;

my $str = "aa";

while ($str ne "zz") {
	print $str++, "\n";
}
print "$str\n";
pi.pl

The above program outputs:

aa
ab
ac
... 670 lines deleted ...
zx
zy
zz

Note that when printing the string, we specify a comma separated list of arguments to the print function. If we had written print "$str++\n";, then ++ would have been treated as if it were a string instead of an operator, the $str scalar would therefore not be updated and the loop would continue forever, displaying the string "aa++".

We do the last print to finish off the output of the last string zz

undef and defined

When a scalar is created in Perl, it is given the initial value of undef (which means that it does not have a meaningful value). We can test for this value by using the defined function. For example, consider the following script.

#!/usr/bin/perl -w

use strict;

my $str;
printf "\$str is %s\n", defined $str ? $str : "<undefined>";

$str = "Hello";
printf "\$str is %s\n", defined $str ? $str : "<undefined>";

$str = undef;
printf "\$str is %s\n", defined $str ? $str : "<undefined>";

$str++;
printf "\$str is %s\n", defined $str ? $str : "<undefined>";
def.pl

We can use the defined function to determine if a variable has been given a value; we can use the undef operator to return a variable to an "uninitialized" state. A variable which is uninitialized has a 0 value when used in a numeric context. When used in a string context, its value is the empty string. Therefore, in the above code, after we explicitly set $str to undef and then increment it, its new value will be 1. (This value is then converted to a string during the subsequent printf operation.)

Note that Perl supports the ternary operator ? : that functions the same way as it does in C and C++. Perl also has a printf function (like C). Because printf is a more expensive function than print, you should use print where possible and use printf only when formatted output is required.

Attempting to display an uninitialized (or undef'ed) variable will trigger the Use of uninitialized value warning when the -w option is used to start Perl. If we attempt to compare a variable with the undef value, we will get the same warning, as demonstrated by the script below. To test whether or not a variable is defined, use defined.

#!/usr/bin/perl -w

use strict;

my $str;

# Warnings: Use of initialized values!
if ($str eq undef) {
	print "\$str is undefined\n";
} else {
	print "\$str is defined\n";
}
undef.pl

As with many scripting languages, we can put comments in our Perl script using the # symbol. The comment continues until the end of the line (like C++'s // comment symbol).

Lists and Arrays (S&P — Chapter 3)

Like C's arrays, Perl supports the concept of an array, which can be though of as a list of elements. Like C++'s vector class, Perl's arrays grow as required, so there is no need to worry about memory allocation issues when storing elements in a Perl array. (Incidentally, we don't have to worry about memory allocation at all in Perl, unlike C and C++). To declare an array variable, we use the special prefix character @. We can iterate over the array by using a foreach loop:

#!/usr/bin/perl -w

use strict;

my @a;

$a[0] = 'a';
$a[3] = 'b';
$a[7] = 'c';

print "Iteration #1\n";
foreach my $v (@a) {
	print defined $v ? "$v " : "undef ";
}
print "\n";

print "\nIteration #2\n";
foreach my $i (0..$#a) {
	print "\$a[$i] = ", defined $a[$i] ? "$a[$i]" : "undef", "\n";
}
print "\n";

# simpler:

print "Iteration #3 (using \$_ default)\n";
for (@a) {
	print defined $_ ? "$_ " : "undef ";
}
print "\n";

print "\nIteration #4 (using \$_ default)\n";
for (0..$#a) {
	print "\$a[$_] = ", defined $a[$_] ? $a[$_] : "undef", "\n";
}
array.pl

There are several things to note about the above program:

In summary, a couple of the popular ways to use for loops in Perl are:

for (@array) {
	# $_ will contain successive values of the @array.
}

and

for (0..9) {
	# $_ will have the values 0, 1, 2, ... 9 (inclusive).
}

List literals, push/pop and shift/unshift

It is common in Perl to initialize an entire array with a list literal rather than initializing each element individually. To do this, we can use a list literal, which is basically a list of scalar values separated by commas and enclosed in parenthesis. For example:

#!/usr/bin/perl -w

use strict;

my @a = ('def', 123);

push @a, 456;
unshift @a, 'abc';

print "@a\n";
print @a, "\n";

print "Popped ", pop @a, " from \@a \n";
print "Shifted ", shift @a, " from \@a\n";

print "@a\n";
ll.pl

Given the initial definition of @a, we have $a[0] eq 'def' and $a[1] == 123. This is more efficient than initializing each array element separately.

We can add elements to the back or front of an array by using the push and unshift functions, respectively. Note that like push_back() for C++ vectors, we don't have to worry about ensuring there is enough room in the Perl array when doing these operations — Perl takes care of this for us. The second argument to push and unshift is actually a list. Therefore we can use push and unshift to add a list of elements to an array. In the above example, the second (scalar) arguments are converted to lists of one element which is then added to the @a array.

The next two print lines demonstrate that can display the values in an array directly without having to use a loop. While the two lines look similar, their output is different:

print "@a\n";	# displays: abc def 123 456
print @a, "\n"; # displays: abcdef123456

When an array is displayed inside double quotes each array element is displayed with a space separating each element. When an array is printed outside of the quotes, the array elements are displayed without an interleaving space character.

pop and shift basically do the opposite of push and unshift, respectively. Each function will remove one element from either the back or front of the array and return that value as a result.


Last modified: March 24, 2004 12:32:21 NST (Wednesday)