Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with shift and dereference operator

Tags:

perl

I have a question regarding how the left and right sides of the -> operator are evaluated. Consider the following code:

#! /usr/bin/perl

use strict;
use warnings;
use feature ':5.10';

$, = ': ';
$" = ', ';

my $sub = sub { "@_" };

sub u { shift->(@_) }
sub v { my $s = shift; $s->(@_) }

say 'u', u($sub, 'foo', 'bar');
say 'v', v($sub, 'foo', 'bar');

Output:

u: CODE(0x324718), foo, bar
v: foo, bar

I expect u and v to behave identically but they don't. I always assumed perl evaluated things left to right in these situations. Code like shift->another_method(@_) and even shift->another_method(shift, 'stuff', @_) is pretty common.

Why does this break if the first argument happens to be a code reference? Am I on undefined / undocumented territory here?

like image 533
user3688180 Avatar asked May 29 '14 15:05

user3688180


1 Answers

The operand evaluation order of ->() is undocumented. It happens to evaluate the arguments before the LHS (lines 3-4 and 5 respectively below).

>perl -MO=Concise,u,-exec a.pl
main::u:
1  <;> nextstate(main 51 a.pl:11) v:%,*,&,x*,x&,x$,$,469762048
2  <0> pushmark s
3  <#> gv[*_] s
4  <1> rv2av[t2] lKM/3
5  <0> shift s*
6  <1> entersub[t3] KS/TARG,2
7  <1> leavesub[1 ref] K/REFC,1
a.pl syntax OK

Both using and modifying a variable in the same expression can be dangerous. It's best to avoid it unless you can explain the following:

>perl -E"$i=5; say $i,++$i,$i"
666

You could use

$_[0]->(@_[1..$#_])
like image 164
ikegami Avatar answered Nov 04 '22 17:11

ikegami