8

According to Perldoc( https://perldoc.perl.org/perlop#Comma-Operator ):

Comma Operator

...

In list context, it's just the list argument separator, and inserts both its arguments into the list. These arguments are also evaluated from left to right.

In following code, I thought $n should be 1 but it became 2. What am I missing?

my $v = 1;
my $n = ( $v, $v = 2 )[0];
# I thought left "$v" would be evaluated (and return 1) first, then right "$v = 2" would.
say "n = $n";  # but output was 2
say "v = $v";  # 2

or

my $v = 1;
my @l = ( $v, $v = 2 );
say Dumper(\@l);   # [ 2, 2 ], not [ 1, 2 ]

even when I changed the order:

my $v = 1;
# my $n = ( $v, $v = 2 )[0];
my $n = ( $v = 2, $v )[1];
say "n = $n";  # still 2
say "v = $v";  # 2
gypark
  • 612
  • 7
  • 26

1 Answers1

8

It does get evaluated left-to-right.

$ perl -MO=Concise,-exec -e'my $v = 1; my $n = ( $v, $v = 2 )[0];'
1  <0> enter v
2  <;> nextstate(main 1 -e:1) v:{
3  <$> const[IV 1] s                   \
4  <0> padsv[$v:1,3] sRM*/LVINTRO       > my $v = 1;
5  <2> sassign vKS/2                   /
6  <;> nextstate(main 2 -e:1) v:{
7  <0> pushmark s                                  \              \
8  <$> const[IV 0] s                               |              |
9  <0> pushmark s                                  |              |
a  <0> padsv[$v:1,3] s                    $v       > ( ... )[0]   |
b  <$> const[IV 2] s                   \           |              > my $n = ...
c  <0> padsv[$v:1,3] sRM*               > $v = 2   |              |
d  <2> sassign sKS/2                   /           |              |
e  <2> lslice sK/2                                /               |
f  <0> padsv[$n:2,3] sRM*/LVINTRO                                 |
g  <2> sassign vKS/2                                             /
h  <@> leave[1 ref] vKP/REFC
-e syntax OK

The catch is that the scalar associated with $v is placed on the stack, not the integer. You can see what's happening here:

use 5.014;
use warnings;

my @stack;

sub sassign {
   my $rhs = pop(@stack);
   my $lhs = pop(@stack);
   $$rhs = $$lhs;
   push @stack, $rhs;
}
                       # Stack     $v   $n
                       # -------   --   --
push @stack, \1;       # 1
push @stack, \my $v;   # 1,$v      !d
sassign();             # $v        1
@stack = ();           #           1

push @stack, \$v;      # $v        1

push @stack, \2;       # $v,2      1
push @stack, \$v;      # $v,2,$v   1
sassign();             # $v,$v     2

pop(@stack);           # $v        2          # Net result of slice.
push @stack, \my $n;   # $v,$n     2    !d
sassign();             # $n        2    2
@stack = ();           #           2    2

say $n;  # 2

If you prefer aliases over references:

use 5.014;
use warnings;
use experimental qw( refaliasing declared_refs );

my @stack;

sub sassign {
   my \$rhs = \pop(@stack);
   my \$lhs = \pop(@stack);
   $rhs = $lhs;
   \$stack[@stack] = \$rhs;
}
                            # Stack     $v   $n
                            # -------   --   --
\$stack[@stack] = \1;       # 1
\$stack[@stack] = \my $v;   # 1,$v      !d
sassign();                  # $v        1
@stack = ();                #           1

\$stack[@stack] = \$v;      # $v        1

\$stack[@stack] = \2;       # $v,2      1
\$stack[@stack] = \$v;      # $v,2,$v   1
sassign();                  # $v,$v     2

pop(@stack);                # $v        2          # Net result of slice.
\$stack[@stack] = \my $n;   # $v,$n     2    !d
sassign();                  # $n        2    2
@stack = ();                #           2    2

say $n;  # 2
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Wow... thank you so much for such detail. While I can't understand the output of B::Concise, the second code in Perl was ease to understand. Now I know what happened inside. However, I still think this behavior is somewhat weird(?). isn't it? – gypark Jan 30 '21 at 12:32
  • Do you find the following weird?: $v =0; f($v, $v); sub f { $_[0]++; $_[1]++ }; print $v; # prints 2 – Dave Mitchell Jan 30 '21 at 23:40
  • @gypark, No, I don't find `$v` putting the scalar `$v` on the stack weird. What's weird is the code posted. Weird code doing unexpected things is not weird. – ikegami Jan 31 '21 at 08:49
  • @DaveMitchell Do I don't, because I know the elements of `@_` are aliases for the arguments from `perldoc perlsub`. :) Maybe I should have read more docs for my question. – gypark Jan 31 '21 at 12:19