AntiGMO
AntiGMO

Reputation: 1587

Assignment of multiple array subroutine parameters in Perl doesn't work

I'm confused about perl subroutine parameters in this example

when i use references in subroutine parameters it works:

@a = ( 1, 2 );
@b = ( 5, 8 );
@c = add_vecpair( \@a, \@b );
print "@c\n";
print $a[0];

sub add_vecpair {    # assumes both vectors the same length
    my ( $x, $y ) = @_;    # copy in the array references
    my @result;
    @$x[0] = 2;

    for ( my $i = 0; $i < @$x; $i++ ) {
        $result[$i] = $x->[$i] + $y->[$i];
    }

    return @result;
}

but when i don't use references as parameters like this:

@a = ( 1, 2 );
@b = ( 5, 8 );
@c = add_vecpair( @a, @b );
print "@c\n";
print $a[0];

sub add_vecpair {    # assumes both vectors the same length
    my ( @x, @y ) = @_;    # copy in the array references
    my @result;
    print @y;
    for ( my $i = 0; $i < @x; $i++ ) {
        $result[$i] = $x[$i] + $y[$i];
    }

    return @result;
}

..it doesn't work. When do i need to use references as subroutine parameters?

Upvotes: 1

Views: 80

Answers (2)

SzG
SzG

Reputation: 12619

When you call Perl subroutines with array or hash parameters, they are flattened out to a single list. Therefore in the second case your two array parameters loose their identities and @_ becomes a single array with the elements of both @a and @b.

Upvotes: 1

Jarmund
Jarmund

Reputation: 3205

Short version: The issue is this line:

my (@x, @y) = @_; 

Assignments are greedy. @x is treated first, and is given as many values from @_ as it can handle. And as it can handle all of them, it ends up getting all of the contents of @_, and @y get none.

The result is the same as this:

my @x = @_;   # Gets all of the arguements
my @y;        # Gets nothing, and is therefore declared but uninitialized.

This is why using references is recommended when subroutines take more than one value as arguement, and at least one of those values are arrays or hashes.


Longer version: @_ is a composite of all of the arguements passed to the subroutine, so the original container doesn't matter. Consider the code snippets below. The first one is yours, the second one does the exact same thing, but more clearly displays what is happening.

@a = (1, 2);
@b = (5, 8);
add_vecpair(@a,@b);

....is the same as:

add_vecpair(1, 2, 5, 8);

To further hilight the problem, hashes get really messy if treated this way:

%a = ('a' => 1, 
      'b' => 2);
%b = ('c' => 3,
      'd' => 4);
somefunction(%a, %b);

...is the same as:

somefunction('a', 1, 'b', 2, 'c', 3, 'd', 4);

Upvotes: 5

Related Questions