my @x = (1 .. 5);
my @y = (6 .. 10);
print_them(@x, @y);
sub print_them {
my (@a, @b) = @_;
print qq{Array \@a is @a\n};
print qq{Array \@b is @b\n};
}
This will print out
Array @a is 1 2 3 4 5 6 7 8 9 10 Array @b iswhich is probably not what you expect or want. The problem here is that the array @_ containing a list of arguments passed into the routine flattens out the list, so that in this example the ``boundary'' between the two arrays @x and @y disappears. In cases like this you can use array references:
my @x = (1 .. 5);
my @y = (6 .. 10);
print_them(\@x, \@y);
sub print_them {
my ($aref, $bref) = @_;
print qq{Array \@a is };
for (@$aref) {
print "$_ ";
}
print qq{\nArray \@b is };
for (@$bref) {
print "$_ ";
}
print "\n";
}
which will output
Array @a is 1 2 3 4 5 Array @b is 6 7 8 9 10Similar considerations hold for returning multiple arrays. Just as for scalar variables, though, you should be aware of the effects of passing in arrays by reference. Consider
my @x = (1 .. 5);
print qq{Before the sub, \@x is @x\n};
test_it(@x);
print qq{After the sub, \@x is @x\n};
sub test_it {
my @a = @_;
print qq{Within the sub, \@a is initially @a\n};
for my $element (@a) {
$element *= 20;
}
print qq{Within the sub, \@a is finally @a\n};
}
which reports
Before the sub, @x is 1 2 3 4 5 Within the sub, @a is initially 1 2 3 4 5 Within the sub, @a is finally 20 40 60 80 100 After the sub, @x is 1 2 3 4 5What happens here is that the array @x gets passed into the subroutine, and a copy of it is made, with the copy being called @a. We then mess with the values of the copy, but upon returning from the subroutine, the original values of @x are unchanged. Consider however passing in the array by reference:
my @x = (1 .. 5);
print qq{Before the sub, \@x is @x\n};
test_it(\@x);
print qq{After the sub, \@x is @x\n};
sub test_it {
my $aref = shift;
print qq{Within the sub, \@a is initially @$aref\n};
for my $element (@$aref) {
$element *= 20;
}
print qq{Within the sub, \@a is finally @$aref\n};
}
In this case we find
Before the sub, @x is 1 2 3 4 5 Within the sub, @a is initially 1 2 3 4 5 Within the sub, @a is finally 20 40 60 80 100 After the sub, @x is 20 40 60 80 100The modifications we did to the array within the subroutine are now reflected in the original values! This is a fundamental property of passing in something by reference, and is analagous to what happens in C when pointers are used. Sometimes this property is very useful and powerful, and sometimes it is annoying - either way, it is something one has to be aware of when working with references.
Passing in and returning hashes from subroutines follows a very similar discussion, as does the need at times for using hash references. Hashes are often used to pass an argument list into a subroutine when many arguments are present; consider
my $name = 'Lianne';
my $age = 22;
my $address = '123 Oak';
my $sin = 12345;
print_info($name, $age, $address, $sin);
sub print_info {
my ($na, $ag, $ad, $si) = @_;
print << "END";
The information we have is
Name: $na
Age: $ag
Address: $ad
SIN: $si
END
}
Here the order of the variables passed into the subroutine
are crucial at getting the correct behaviour. However, if
we write this using hashes as
my $name = 'Lianne';
my $age = 22;
my $address = '123 Oak';
my $sin = 12345;
print_info(name => $name,
address => $address,
age => $age,
sin => $sin);
sub print_info {
my (%info) = @_;
print << "END";
The information we have is
Name: $info{name}
Age: $info{age}
Address: $info{address}
SIN: $info{sin}
END
}
then we have an effective ``named'' argument list and can
pass in the arguments in any order we choose.