Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

In the code below, I pass the array @num as a reference to the subroutine second. At second, the array is changed and some value (not directly related to the array) is returned to the calling sub. I want to preserve the value of the original array @num after the operation at second. What is the best way to do that?

use strict; my @num = qw(1 2 3 4 5); first(); sub first { print "\@num before: @num\n"; # prints 1 2 3 4 5 my $result = second(\@num); print "result: $result\n"; print "\@num after: @num\n"; # prints 1 2 3 4 5 6 # But I would need it to still print # 1 2 3 4 5 } sub second { my $num_ref = shift; push(@$num_ref, 6); my $sum = 0; foreach (@$num_ref) { $sum += $_; } return $sum; }
Thank you so much.

Replies are listed 'Best First'.
Re: Preserve the value of original array
by bobf (Monsignor) on Feb 14, 2006 at 06:09 UTC

    You could make a copy of the array in second(), but that wouldn't be very efficient if your array is large. If your real code is sufficiently similar to the example you could simply use a different array (or no array at all - just add values to the list that foreach iterates over). For example:

    sub second { my $num_ref = shift; my $sum = 0; my @newarray = ( 6 .. 10 ); # try one of these options # foreach ( @$num_ref, 6 .. 10 ) { foreach ( @$num_ref, @newarray ) { $sum += $_; } return $sum; }
    Either option should accomplish what you asked. If you don't want to modify the array in second(), don't modify the array. :-)

    HTH

    Update: If you really do want to make a copy of the array, simply pass the array to the sub rather than passing an array ref:

    my $result = second( @num ); sub second { my ( @array ) = @_; # etc
    or pass an array ref and then copy it into a new array:
    my $result = second( \@num ); sub second { my ( $aref ) = @_; my @new_array = @$aref; # my $new_ref = [ @$aref ]; # alternative
    Please note that simply copying the array reference will not work, as it is still a reference to the original array.

      Thanks, bobf

      I need to pass the array as a reference because I'm passing more than one value. My example was simplified to make my question simpler.

        It's a little bit harder to answer when your example is thus simplified. It looks like you got your answer, anyway.

        (I might've suggested:)

        sub second { my $sum = 0; $sum += $_ for 6, @{+shift}; $sum }
Re: Preserve the value of original array
by McDarren (Abbot) on Feb 14, 2006 at 06:07 UTC
    I want to preserve the value of the original array @num after the operation at second. What is the best way to do that?
    Just take a copy of it in your second sub and work on that. For example:
    sub second { my $num_ref = shift; my @copy_of = @$num_ref; push(@copy_of, 6); my $sum = 0; foreach (@copy_of) { $sum += $_; } return $sum; }
    Cheers,
    Darren :)
      Thanks, Darren :)

      I need to copy the array into an array, and not make a copy of the reference, as in:

      sub second { my $num_ref = shift; my $copy_of_ref = $num_ref; push(@$copy_of_ref, 6); my $sum = 0; foreach (@$copy_of_ref) { $sum += $_; } return $sum; }
      Am I right?
        Yes, that's fine. But please also take note of bobf's comments below :)

        Update:Actually, I misread what you said there. Either way is okay. You can either take a copy of the reference, or dereference it into another array. But again, as bobf already pointed out in his update - the simplest way is to just pass the array (rather than a reference) - and then take a copy of that.

Re: Preserve the value of original array
by Anonymous Monk on Feb 14, 2006 at 06:12 UTC

    Hai, Don't dereference the original array. Instead of dereference just store it in different array in the second subroutine.

    use strict; my @num = qw(1 2 3 4 5); first(); sub first { print "\@num before: @num\n"; # prints 1 2 3 4 5 my $result = second(\@num); print "result: $result\n"; print "\@num after: @num\n"; # prints 1 2 3 4 5 6 # But I would need it to still print # 1 2 3 4 5 } sub second { my @num_ref = shift; push(@num_ref, 6); my $sum = 0; foreach (@num_ref) { $sum += $_; } return $sum; }