Guru
Guru

Reputation: 17014

Perl: Special array @_ is not really an alias?

The special array, @_ , where all the arguments passed to a function are present, is actually an alias to the arguments passed. Hence, any change we make directly to this special array @_ will reflect in the main as well. This is clear.

#!/usr/bin/perl

use warnings;
use strict;

$\="\n";

sub func {
        print \@_;
        $_++ for(@_);
}

my @arr=(2..4);
print \@arr;
func(@arr);
print "@arr";

For the above program, I expected the reference of @arr and @_ to point to the same location since it is an alias. But it is not so.

On running the above:

ARRAY(0x1b644d0)
ARRAY(0x1b644e0)
3 4 5

If they are pointing to 2 different locations, how the changes done in @_ is reflecting in @arr?

Am I seeing something wrong? Please advice.

Upvotes: 12

Views: 1062

Answers (2)

ikegami
ikegami

Reputation: 386451

@_ isn't aliased; its elements are.

Remember that

func(@arr);

is the same as

func($arr[0], $arr[1], ...);

because the only thing that can be passed to a sub is a list of scalars, and an array evaluates to a list of its elements in list context.

So that means

func(@arr);

is basically the same as

local @_;
alias $_[0] = $arr[0];
alias $_[1] = $arr[1];
...
&func;

Changing the elements of @_ will change elements of @arr, but adding and removing elements of @_ won't change @arr since they are different arrays.

>perl -E"@a=(4..6); sub { $_[0] = '!';        say @_; }->(@a); say @a;"
!56
!56

>perl -E"@a=(4..6); sub { splice(@_,0,1,'!'); say @_; }->(@a); say @a;"
!56
456

Upvotes: 11

perreal
perreal

Reputation: 98088

This might answer you question:

use warnings;
use strict;

$\="\n";

sub func {
        print \@_;
        $_++ for(@_);
        print \$_ for @_; 
}

my @arr=(2..4);
print \@arr;
func(@arr);
print "@arr";
print \$_ for @arr;

Output

ARRAY(0x17fcba0)
ARRAY(0x1824288)
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)
3 4 5
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)

As you see, individual arguments have the same address but the container is not the same. If you push an item to @_ in func the @arr will not change (so you can do shift in funct). So, each argument is an alias and array elements are passed as individual items. @_ contains all items passed into the subroutine. If you want to modify an array argument you need to pass it by reference.

Upvotes: 17

Related Questions