I need a subroutine that completely removes an array element in place. The following code fails:
sub del
{
splice(@_,2,1);
}
@array=(0..5);
print "@array"."\n";
del(@array);
print "@array"."\n";
The same array is printed again, i.e. the element has not been removed.
However, if I use the splice()
in the main body of the program instead of calling a subroutine, it works.
While the scalar elements of @_
are aliased to the data which is passed in, @_
itself is a different variable. This means $_[1] = "foo"
will alter $_[1]
but push @_, "foo"
will not alter @_
. Otherwise my $self = shift
would be a Bad Thing.
You need to pass in the array as a reference.
sub del {
my $array_ref = shift;
splice @$array_ref, 2, 1;
return;
}
del \@array;
If you absolutely must keep the del @array
interface, this is one of the few places where it's appropriate to use a prototype.
sub del(\@) {
my $array_ref = shift;
splice @$array_ref, 2, 1;
return;
}
del @array;
The \@
prototype tells Perl to pass in @array
by reference. I would recommend against doing this for two reasons. First, prototypes have a pile of caveats which make them not worth the trouble.
More importantly, it makes it non-obvious that del
will modify its arguments. Normally user defined Perl functions copy their arguments, so you can look at foo @array
and be reasonably sure @array
will not be altered by foo
. This enables one to skim the code quickly for things which will affect a variable. A reference prototype throws this out the window. Now every function must be examined for a possible hidden pass-by-reference.