in reply to print behavior

Remember that arguments are passed by reference*, so print will see the change in $x caused by ++ (which must be evaluated before print is called).

In detail,

print $x, $x++;

is roughly equivalent to

{ local @_; alias $_[0] = $x; alias $_[1] = $x++; &print; }

except the order of the alias statements isn't defined.

Given $x=0, @_ is ($x, $anon) which evaluates to (1, 0).

In short, avoid modifying a variable in a parameter list expression when the variable appears elsewhere in that parameter list.

* — "by reference" is different than "as a reference".

Replies are listed 'Best First'.
Re^2: print behavior
by atemon (Chaplain) on Jul 10, 2007 at 09:24 UTC

    With due respect to ikegami and all other monks, I strongly disagree with ikegami for the following reasons.

    1. How will you explain the peculiar behavior I have explained in my post Re: print behavior when we have more than one $x++ in same print statement ? ( the table is appended below for reference.

      Print orderO/P in Perl
      $x0
      $x,$x++10
      $x,$x,$x++110
      $x,$x++,$x++201
      $x,$x++,$x++,$x++3012
      $x,$x++,$x++,$x++,$x++40123
      $x,$x++,$x++,$x++,$x++,$x++501234

    2. How we have the similar behaviour with "C" where printf("%d%d",x,x++) which will also print 10?
    3. you said "print will see the change in $x caused by ++ (which must be evaluated before print is called)." Then why
      my $x =0; print $x++; #prints 0 print $x++; #prints 1
      works properly? Why in this case $x++ is NOT incrementing $x before print is called?
    4. Given $x=0, @_ is ($x, $anon) which evaluates to (1, 0). --- Can you explain how the @_ is evaluated to ( 1, 0 ) ?
    5. arguments are passed by reference --- if its passed by reference, how will you explain this behaviour for all function calls? including user-defined-functions? (see comments in my post Re: print behavior)

    If you keep the explanation I posted at Re: print behavior in mind, there is NO harm in modifying a variable in a parameter list expression when the variable appears elsewhere in that parameter list. Isn't it a nice obfuscation.

      That's a lot of questions! Here goes...

      Answer to Question 1

      I'll do two examples, $x,$x,$x++:

      { local @_; alias $_[0] = $x; alias $_[1] = $x; alias $_[2] = $x++; &print; # @_ = ($x, $x, $anon) = (1, 1, 0) }

      $x,$x++,$x++:

      { local @_; alias $_[0] = $x; alias $_[1] = $x++; alias $_[2] = $x++; &print; # @_ = ($x, $anon1, $anon2) = (2, 1, 0) }

      $x,$x++,$x++, on a system that does the alias statments in a different order:

      { local @_; alias $_[2] = $x++; alias $_[1] = $x++; alias $_[0] = $x; &print; # @_ = ($x, $anon1, $anon2) = (2, 0, 1) }

      Answer to Question 2

      Your compiler probably does something like:

      load x inc push load x push call printf

      C doesn't guarantee the order either.

      Answer to Question 3

      The return value of $x++ is not $x. It's a new variable that contains the old value of $x. $x is incremented before the print call, but you are aren't printing $x. Check perlop.

      Answer to Question 4

      # $x | anon returned | $_[0] | $_[1] # | by $x++ | | # ------+-----------------+---------+--------- my $x = 0; # 0 | -- | -- | -- { # 0 | -- | -- | -- local @_; # 0 | -- | undef | undef alias $_[0] = $x; # 0 | -- | 0 | undef alias $_[1] = $x++; # 1 | 0 | 1 | 0 &print; }

      or in even more detail

      # $x | anon returned | $_[0] | $_[1] # | by $x++ | | # ------+-----------------+---------+--------- my $x = 0; # 0 | -- | -- | -- { # 0 | -- | -- | -- local @_; # 0 | -- | undef | undef alias $_[0] = $x; # 0 | -- | 0 | undef my $anon = $x++; # 1 | 0 | 1 | undef alias $_[1] = $anon; # 1 | 0 | 1 | 0 &print; }

      Answer to Question 5

      Guess what the following prints:

      perl -le"$x=3; sub { $_[1]++; $_[2]++; print @_ }->($x+0, ++$x, $x++, +$x+0, $x);"

      On my system, it prints 36556.

      my $x = 3; # $anon0 | $x | $anon2 | $anon3 | $x { # $_[0] | $_[1] | $_[2] | $_[3] | $_[4] local @_; # --------+-------+--------+--------+------- # $x+0 my $anon0 = $x+0; alias $_[0] = $anon0; # 3 | -- | -- | -- | -- # ++$x $x=$x+1; # 3 | -- | -- | -- | -- alias $_[1] = $x; # 3 | 4 | -- | -- | -- # $x++ my $anon2 = $x; alias $_[2] = $anon2; # 3 | 4 | 4 | -- | -- $x=$x+1; # 3 | 5 | 4 | -- | -- # $x+0 my $anon3 = $x+0; alias $_[3] = $anon3; # 3 | 5 | 4 | 5 | -- # $x alias $_[4] = $x; # 3 | 5 | 4 | 5 | 5 &anon_sub; # $_[1]++; # 3 | 6 | 4 | 5 | 6 # $_[2]++; # 3 | 6 | 5 | 5 | 6 # print @_; }

      Notice how $x and $x+0 are different.
      Notice how $_[1]++ affects more than one argument.
      Notice how $_[1]++ affects $x and ++$x.
      Notice how $_[1]++ doesn't affect $x+0 and $x++.