In the following script, I declare and modify @basearray in the main program. Inside the dosomething subroutine, I access @basearray, assign it to an array local to the script, and modify the local copy. Because I have been careful to change the value only of local variables inside the subroutine, @basearray is not changed.
If I had made the mistake of assigning a value to @basearray inside the subroutine, though, it would have been changed and that value would have persisted after the call to the subroutine.
This is demonstrated in the 2nd subroutine, doagain.
Also, doagain receives the reference \@basearray as an argument rather than accessing @basearray directly. But going to that additional trouble provides no additional safety. Why do it that way at all?
Is there a way to guarantee that I cannot inadvertently change @basearray inside any subroutine? Any kind of hard safety device that I can build into my code, analogous to use strict;, some combination perhaps of my and local?
Am I correct in thinking that the answer is No, and that the only solution is to not make careless programmer errors?
#!/usr/bin/perl
use strict; use warnings;
my @basearray = qw / amoeba /;
my $count;
{
print "\@basearray==\n";
$count = 0;
foreach my $el (@basearray) { $count++; print "$count:\t$el\n" };
}
sub dosomething
{
my $sb_name = (caller(0))[3];
print "entered $sb_name\n";
my @sb_array=( @basearray , 'dog' );
{
print "\@sb_array==\n";
$count = 0;
foreach my $el (@sb_array) { $count++; print "$count:\t$el\n" };
}
print "return from $sb_name\n";
}
dosomething();
@basearray = ( @basearray, 'rats' );
{
print "\@basearray==\n";
$count = 0;
foreach my $el (@basearray) { $count++; print "$count:\t$el\n" };
}
sub doagain
{
my $sb_name = (caller(0))[3];
print "entered $sb_name\n";
my $sf_array=$_[0];
my @sb_array=@$sf_array;
@sb_array=( @sb_array, "piglets ... influenza" );
{
print "\@sb_array==\n";
$count = 0;
foreach my $el (@sb_array) { $count++; print "$count:\t$el\n" };
}
print "now we demonstrate that passing an array as an argument to a subroutine does not protect it from being globally changed by programmer error\n";
@basearray = ( @sb_array );
print "return from $sb_name\n";
}
doagain( \@basearray );
{
print "\@basearray==\n";
$count = 0;
foreach my $el (@basearray) { $count++; print "$count:\t$el\n" };
}