I encountered a strange bug while using @_ to pass a single argument to a Perl subroutine. The value passed to a subroutine changes right after entering the subroutine.
Code example:
my $my_def = 0;
print "my_def = $my_def \n";
@someResult = doSomething($my_def);
sub doSomething {
my $def = @_;
print "def = $def \n";
...
}
This returned:
> my_def = 0
> def = 1 # instead of "0"
One more strange thing is that the code worked right for several months before.
The problem was resolved, when I changed it to:
sub doSomething {
my $def = $_[0];
Could anyone tell what could cause the problem? Are there any limitations in using @_ to pass a single argument?
Thanks!
You're getting the correct behaviour, although it isn't what you expected.
A simple rule of thumb for getting local variables from the arguments in a subroutine is to always use parentheses around the variable list in the my (...)
declaration:
sub do_something
{
my ($def) = @_;
...
}
The difference is between list context and scalar context. In scalar context, all arrays return the number of elements in the array: 1 in your case. And when you wrote my $def = @_
you provided scalar context. When you used my $def = $_[0]
instead you explicitly accessed element zero of the array, which is a scalar (hence the $
sigil) so it all worked again.
In the general case you might have:
sub do_something_else
{
my ($arg1, $arg2, $arg3, @the_rest) = @_;
...
}
Now you have three scalar local variables, $arg1
, $arg2
, and $arg3
, and one array, @the_rest
that collects any extra arguments passed.