14

I've got some code that doesn't work the way I expect, and I'd appreciate some help figuring out how to get it working the way I DO expect.

I'd like to use a subroutine to modify an input array. I figured that if I passed in a reference to the array, any changes I made to it would be reflected in the caller's version, too. But it apparently doesn't work that way.


my @test_array = qw (zero one two three);

shift_array(\@test_array);
print "POST SUBROUTINE: $test_array[0]\n";

sub shift_array {
    my @array = @{(shift)};
    shift @array;
    print "AFTER SHIFT IN SUB: $array[0]\n";
}

This prints:

AFTER SHIFT IN SUB: one
POST SUBROUTINE: zero

I expected it to print one both times.

So my question is two-fold:

1) Why isn't it behaving the way I think it should? Does passing a reference to an array create a copy of the array?

2) How do I get the behavior I WAS expecting? How do I I get a subroutine to slide one or more elements off of the front of caller's copy of an input array?

Thanks in advance for any insight you can offer.

3 Answers 3

11

Because my @array is a new array that you assigned the dereferenced original array to. It's a copy.

Instead do this:

sub shift_array {
    my $array = shift;
    shift( @$array );
}

Edit: I originally said dereferencing it creates the problem but using @$array is still dereferencing it. As @mob pointed out, assigning the variable is what creates the new array instead of updating the existing reference.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow. That's a nuance I did not understand. Thanks!
note that with perl 5.14+ you can write shift $array in the sub and the de-referencing happens automagically.
1

This is one of the (tiny number) of cases where Perl prototypes are useful.

#!/usr/bin/perl

use strict;
use warnings;

# Prototype forces the first argument to be a reference to an array    
sub shift_array (\@) {
  my $array = shift;
  shift(@$array);
  print "AFTER SHIFT IN SUB: @$array[0]\n";
}

my @test_array = qw (zero one two three);

shift_array(@test_array);
print "POST SUBROUTINE: $test_array[0]\n";

Comments

1

I prefer to be more consistent in the use of array references to minimize ambiguity:

#!/usr/bin/perl
use strict;
use warnings;

my @test_array = qw (zero one two three);

shift_array(\@test_array);
print "POST SUBROUTINE: $test_array[0]\n";

sub shift_array {
    my $ref = shift;
    shift @$ref;
    print "AFTER SHIFT IN SUB: ${$ref}[0]\n";
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.