March 17 (Wednesday) March 22 (Monday)
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";
ll2.pl
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.
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";
sub.pl
There are several important points about the above subroutine that you should notice:
sub
keyword and is given a name (sum
in this example).
return
operator.
@_
(not to be confused with the default scalar variable
$_
). We can refer to the first parameter by saying
$_[0]
, the second parameter by saying $_[1]
and so on. Again, do not confuse $_[0]
with $_
.
They represent different scalars.
my
list as follows:
my ($num1, $num2) = @_;
Note that $num1
and $num2
are local to the
sum
subroutine and cannot be accessed outside of it.
This means that my
variables are statically scoped.
(Perl also supports dynamic scoping as well via the (poorly
named) local
operator, but we will not be discussing this.
See page 63 of S&P for all the details if you are curious.)
&
symbol and enclosing the parameters inside
parenthesis. As can be seen by the above script, we can pass in
literals, scalar variables, or even a list. The expected results
happen in all cases.
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 += $_;
}
$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";
sub2.pl
Again, there are several things to note about the above script:
@_
argument list via the for
loop.
The default scalar $_
will implicitly assume all the
values (if any) in the parameter list and a running total is maintained
via the sum
local variable.
$sum
in the above code). We do
not need to explicitly use the return
keyword to return a
value from a subroutine. We typically use return
in a
Perl subroutine if we wish to exit the subroutine early (due to an
error condition, for example).
..
".
print "No numbers given!\n" if ! @_;
demonstrates a sort of 'postfix' form of the if
statement
and is quite commonly used in Perl when the body of an if
statement is a single line. (This notation can also be used for
while
loops as well.) Note that there are no parenthesis
required around the condition being tested by the if
.
The condition, by the way, is the negation of the @_
parameter array used in list context. This condition will return
true if the parameter array has zero elements.
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";
&scalar_pass($var);
print $var;
# Error! Modification of a read-only value attempted
#&scalar_pass("Hi");
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);
sub3.pl
scalar_pass
method, we copy the parameters
to the local $value
variable and then append a string to
it. This does not affect the actual parameter itself, which is
$var
in the first invocation of scalar_pass
and the literal "Hi"
in the second invocation. We
then append another string to the $_[0]
array element.
This modifies the $var
parameter in the first invocation,
but causes an error on the second invocation of scalar_pass
because the second invocation used a string literal which cannot
be modified. Therefore, if you copy the values from the @_
parameter list to local variables you are achieving pass by value
semantics. Using the elements of the @_
array directly
(e.g. $_[0]
) results in pass-by-reference semantics.
list_pass
demonstrates Perl's
default tendency to 'flatten' lists that are passed in as actual
parameters. The argument to the invocation of list_pass
is the list (1, 2, 3, 4, 5)
. Inside the function
itself, the assignment my ($var, @list) = @_;
assigns
the first scalar in the argument list to $var
and the
@list
variable absorbs all the rest of the arguments,
as shown by the output.
Last modified: March 20, 2004 20:01:03 NST (Saturday)