I'm looking for perl docs confirming the following behaviour, where passed @_ still holds the first argument, despite shift() which alters @_.
use Data::Dumper;
sub f { shift->(@_) }
f(sub{ print Dumper \@_ }, 1,2);
output
$VAR1 = [
sub { "DUMMY" },
1,
2
];
You are asking about the order in which the shift
is performed relative to creation of the argument list.
It's not documented.
Rely on this at your own risk, but Perl always evaluates the left of the ->
last in a call (so that the code reference is topmost on the stack).
In the following, you can see that @_
(lines 3 and 4) is evaluated before shift
(line 5).
$ perl -MO=Concise,-exec,f -e'
use Data::Dumper;
sub f { shift->(@_) }
f(sub{ print Dumper \@_ }, 1,2);
'
main::f:
1 <;> nextstate(main 1266 -e:3) v
2 <0> pushmark s
3 <#> gv[*_] s
4 <1> rv2av[t2] lKM/1
5 <0> shift s*
6 <1> entersub[t3] KS/TARG
7 <1> leavesub[1 ref] K/REFC,1
-e syntax OK
Let's walk through it.
@_
initially contains scalars A, B and C.@_
so that it now contains B and C.Solution: Avoid reading and modifying the same variable in the same expression.
sub f { $_[0]->( @_[ 1 .. $#_ ] ) }
sub f { my $cb = shift; $cb->( @_ ) }
sub f { my $cb = shift; &$cb }
sub f { &{ +shift } }
Or if you want to remove the stack frame for f
from the stack (hiding it from caller
and croak
), you can use the following:
sub f { my $cb = shift; goto &$cb }