Question

In perl all sub's argument writting to @_ array, like this:

call_any_sub($a,$b,$c);
sub call_any_sub {
  my $s_a = shift;
  my $s_b = shift;
  my $s_c = shift;
}

But, if i want to passed array as an argument to sub, i should use:

call_any_sub(@data_array);
sub call_any_sub {
  my @data = @_;
}

Instead of similar:

call_any_sub(@data_array);
sub call_any_sub {
  my @data = shift;
}

So, why @data_array replaces the array of arguments and not written in it (as expected)?

Was it helpful?

Solution 2

You need to understand what shift does.

The shift/unshift pair of commands are parallel to the pop/push pair of commands. All of these commands operate on arrays. By default, shift (and only shift) assumes the @_ array when called in a subroutine and @ARGV when called in the main program. This means the following two statements are identical in a subroutine:

my $foo = shift @_;  # Explicit Argument
my $foo = shift      # Implicit Argument

Perl's parameter passing is an interesting concept because it doesn't really do named parameter passing like almost all other programs. Instead, everything is passed as one long list of scalars. This makes it hard when you aren't passing in a scalar.

It works okay if I am only passing in a single hash or array:

munge_hash ( %foo );

sub munge_hash {
    my %hash = @_;
    ...

}

And, you have to be careful if you're passing in multiple arguments and an array. In this case, the array must be the last in your list of arguments:

my $foo = "floop";
my $bar = "bloop";

my @array = qw(loop coop soop);

munge_this ( $foo, $bar, @array );

sub munge_this {
   say join ":", @_;  # Prints "floop:bloop:loop:coop:soop"
   my $var1 = shift   # floop
   my $var2 = shift   # bloop
   my @arry = @_      # The rest is the array passed.

However, things really fall apart if you're passing in multiple arrays or hashes. All of the elements get merged into a single list of scalars represented by @_.

munge_two_arrays ( @foo, @bar );

sub munge_two_arrays {
    # Problem! Elements of both arrays are in @_.
    # How do I separate them out?
}

Thus, it is common not to pass in a whole array, but an array reference:

munge_two_arrays( \@foo, \@bar ); # These are array references

sub munge_two_arrays {
    my $array1_ref = shift;
    my $array2_ref = shift;

    my @array1 = @{ $array1_ref } # Dereference array references to make arrays
    my @array2 = @{ $array2_ref } # Dereference array references to make arrays
}

This keeps the values of the two arrays from getting merged into a single @_.

OTHER TIPS

One can only pass a list of scalars to a subroutine (and that's all they can return). After all, the arguments are presented to the sub as an array (@_), and arrays can only contains scalars.

You can either (inefficiently) recreate the array in the sub

 sub foo {
    my @bars = @_;
    say for @bars;
 }

 foo(@bars);

or you can pass a reference to the array

 sub foo {
    my ($bars) = @_;
    say for @$bars;
 }

 foo(\@bars);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top