next up previous contents index
Next: References to subroutines Up: Subroutines, functions, and modules Previous: Returning variables   Contents   Index

Passing in and returning arrays and hashes

Passing in and returning arrays and hashes from subroutines involves some subtelties. Consider
  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 is
which 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 10
Similar 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 5
What 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 100
The 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.
next up previous contents index
Next: References to subroutines Up: Subroutines, functions, and modules Previous: Returning variables   Contents   Index