March 19, 2004 (Friday)

Lists and Arrays (S&P — Chapter 3, cont'd)

The qw short cut, list assignment and list/scalar context

Using the ('...', '....', ...) notation described above to create a list literal of string scalars can be quite cumbersome. Therefore Perl allows you to create a list literal of strings using the qw construct as demonstrated by the following code:

#!/usr/bin/perl -w

use strict;

my @a = qw/this is a list/;	# equivalent to ('this', 'is', 'a', 'list')

print join(",", @a), "\n";

my ($one, $two) = @a;
print "$one/$two\n";

my ($a, $b, $c, $d, $e) = @a;
print "$a,$b,$c,$d,$e\n";

my ($val1) = @a;

my $val2 = @a;

print "$val1 $val2\n";

@a = sort @a;
print "@a\n";

All the elements of the list are specified between the /.../ delimiters (you can actually use any pair of corresponding delimiters for the qw construct). This notation makes the creation of lists of strings much easier.

The above code also demonstrates the use of the join function which takes a delimiter string and an array. It will create a string which consists of all the elements of the array separated by the specified delimiter string.

The code my ($one, $two) = @a; shows how we can extract elements from a list and assign them to scalars. In this code fragment, the variable $one will get the first element of the list and $two will get the second element. This is equivalent to saying:

my $one = $a[0];
my $two = $a[1];

If we try to assign more variables than there are elements in the list, then the remaining variables will be left as undef. For example, in the statement my ($a, $b, $c, $d, $e) = @a;, the variable $e will not be defined, since the array has only four elements. Note that when declaring more than one variable with my, you must include the variables inside parenthesis.

The two statements:

my ($val1) = @a;
my $val2 = @a;

demonstrate the importance of list context versus scalar context. In the first case, $val1, because it is being declared inside parenthesis, is in list context. This means that @a will also be treated as a list. When the assignment happens, $val1 will get the value of the first element of the array @a. In the second assignment, however, $val2 is in scalar context, therefore @a will be evaluated as a scalar. When an array is evaluated as a scalar, it returns the number of elements in the array. Therefore, the statement print "$val1 $val2\n"; will display this 4. We can force scalar context by using the scalar keyword in Perl. For example if we wanted to display the number of elements in an array we can write:

print scalar @a;

(Remember that just writing print @a; would display the elements in the array not the number of elements. Also note that the length function returns the number of characters in a scalar — it cannot be used to determine the number of elements in an array.)

There are other important situations where list and scalar context arise. See page 51 of S&P for details.

The final couple of statements in the above code demonstrate the use of the sort function which sorts an array. Note that there is no harm in using the same variable on the left- and right-hand side of the assignment when doing the sorting. Note that arrays are lexicographically sorted. Therefore, the statement:

print join(",",sort (123, 9, 50)), "\n";

will display 123,50,9 because the list is being sorted alphabetically, and not numerically. (We'll see how to do numeric sorts later.) Another function called reverse can be used to reverse arrays.

Another use of list assignments is to swap to scalars. For example, the code fragment ($v1, $v2) = ($v2, v1) will swap the values stored in the scalar variables $v1 and $v2. There is no need to introduce a temporary variable.

Subroutines (S&P — Chapter 4)

As in C and C++, Perl has the concept of a function or subroutine, as they are called in Perl. For example, here is a simple subroutine that adds two numbers and returns the result:

#!/usr/bin/perl -w

use strict;

sub sum {
	my ($num1, $num2) = @_;

	return $num1 + $num2;

print &sum(12, 43), "\n";

my ($v1, $v2) = (100, 10);
print &sum($v1, $v2), "\n";

my @a = (1, 2);
print &sum(@a), "\n";

There are several important points about the above subroutine that you should notice:

The above subroutine is a bit restrictive in that it only sums up two numbers. We can make our subroutine more flexible by allowing it to sum up a variable number of arguments:

#!/usr/bin/perl -w

use strict;

sub sum {
	my $sum = 0;

	print "No numbers given!\n" if ! @_;
	for (@_) {
		$sum += $_;

print &sum(12, 43, 67, 98), "\n";

my ($v1, $v2) = (100, 10);
print &sum($v1, $v2), "\n";

my @empty = ();
print &sum(@empty), "\n";

print &sum(1..100), "\n";

Again, there are several things to note about the above script:

Some brief notes about subroutine parameter passing

The following Perl script demonstrates some features about parameter passing in Perl:

#!/usr/bin/perl -w

use strict;

sub scalar_pass {
	my ($value) = @_;
	$value .= " World";
	$_[0] .= " There\n";

my $var = "Hello";
print $var;

# Error! Modification of a read-only value attempted

sub list_pass {
	my ($var, @list) = @_;
	print "$var (@list)\n";  # displays 1 (2 3 4 5) 

my @l = (3, 4, 5);
&list_pass (1, 2, @l);

Last modified: March 20, 2004 20:01:03 NST (Saturday)