Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

question 1st - undefined behaviour

by rumos2 (Novice)
on Sep 23, 2013 at 21:53 UTC ( #1055390=perlquestion: print w/replies, xml ) Need Help??
rumos2 has asked for the wisdom of the Perl Monks concerning the following question:

Maybe easy, maybe not, but:

my $x=5; $x=$x + ++$x + $x++; warn $x; #get 18.

How I undestand that:
1)$x - return's copy of object $x and then return it's value in numeric context.
2)++$x - make increment, but return object $x, this mean that in future if we change it's value also been changed.
3)$x++ - make increment, but return's not icremented copy of object $x.
points 2 and 3 I've check im many examples.
I'm not sure about point 1, because by logic - it must place here original $x, so value must be calculated as 20 (7+7+6)

So this not working code, I know that this is incorrect and can't be submited in production code. It's for my students for good undestanding of this situation.

Will be happy for any answers with proof-links or for answers from greatest monks )

Replies are listed 'Best First'.
Re: question 1st - undefined behaviour
by AnomalousMonk (Chancellor) on Sep 23, 2013 at 23:52 UTC

    Another approach is to ask Perl what it thinks about the code you've written (with further reference to perlop):

    >perl -wMstrict -MO=Deparse,-p -le "my $x = 5; $x = $x + ++$x + $x++; warn $x; " BEGIN { $^W = 1; } BEGIN { $/ = "\n"; $\ = "\n"; } use strict 'refs'; (my $x = 5); ($x = (($x + (++$x)) + ($x++))); warn($x); -e syntax OK >perl -wMstrict -le "my $x = 5; $x = $x + ++$x + $x++; warn $x; " 18 at -e line 1.

    See O and B::Deparse.

      thanks. most complete answer. and no any magic.

        thanks. most complete answer. and no any magic.

        It also doesn't explain the unexplainable :)

Re: question 1st - undefined behaviour
by dave_the_m (Prior) on Sep 24, 2013 at 07:01 UTC
    If you run your code under a perl built with -DDEBUGGING, which can show each instruction being executed and what's on the stack after each execution, things may become clearer.

    Here's the output of perl -Dst -e'my $x=5; $x=$x + ++$x + $x++;' with some annotations. I've skipped the first assign statement.

    The padsv op pushes $x (not a copy) onto the perl stack; $x is currently an integer value (IV) with value 5: (-e:1) padsv($x) => IV(5) $x is pushed onto the stack again: (-e:1) padsv($x) => IV(5) IV(5) preinc increments the variable $x; note that both values on the stack have now incremented (because they are both $x, not copies) (-e:1) preinc => IV(6) IV(6) the add op takes the top two values on the stack and replaces them with a new value: (-e:1) add => IV(12) push $x again. Since it was preinc()ed earlier, it now has the value 6: (-e:1) padsv($x) => IV(12) IV(6) postinc takes the variable $x off the stack, makes a copy and pushes that copy back on the stack, then increments $x. If we had any other direct $x's on the stack (which we don't), their values would appear incremented: (-e:1) postinc => IV(12) IV(6) the final add does the obvious thing. (-e:1) add => IV(18)
    Note that this is what currently *happens* to happen. Code should not rely on this behaviour.


Re: question 1st - undefined behaviour
by boftx (Deacon) on Sep 23, 2013 at 23:23 UTC

    As someone else already mentioned, you really should take a look at just exactly what the pre- and post-increment operators are doing and when.

    Also, and even more importantly, you have made a major error in thinking that your code snippet from your comment above ($x = ++$x + $x++ + $x) is the same as in your OP, which was $x = $x + ++$x + $x++. They are entirely different.

    Here is a simple program to demonstrate the point:

    #!/usr/bin/perl use strict; use warnings; my $x = 5; $x = $x + ++$x + $x++; print "x: $x\n"; my $y = 5; # avoid any contamination from first group. $y = ++$y + $y++ + $y; print "y: $y\n"; exit; __END__ Output: [~/perl/test]# ./ x: 18 y: 20
    On time, cheap, compliant with final specs. Pick two.
      -we post it in close time))
      I understand that,
      $x=$x + ++$x + $x++ and
      $x=++$x + $x++ $x
      entirely different, I've just want to understand:
      1. does $x++ return an object copy before incrementing it's value?
      2. does ++$x return original object, but not value of $x after $x incrementation ?
      3. why in first example ($x + ++$x + $x++ ) first $x is used as a copy of $x for the moment when it's not been changed, and in second example (++$x + $x++ + $x) we get not copy of $x but original $x.

      And I don't seeking for
      Note that just as in C, Perl doesn't define when the variable is incremented or decremented. You just know it will be done sometime before or after the value is returned. This also means that modifying a variable twice in the same statement will lead to undefined behavior. I want to understand, and search for any document or c++-source, which describe what exactly happens here and why.
Re: question 1st - undefined behaviour
by ikegami (Pope) on Sep 24, 2013 at 19:03 UTC
    If you want to see what's happening, you can step through the following:
    use strict; use warnings; use Data::Alias qw( alias ); my @stack; # Increments the scalar on the stack. sub preinc { alias my $i = pop(@stack); ++$i; alias push @stack, $i; } # Increments the scalar on the stack. # Returns a new scalar with the original # value of the scalar on the stack. sub postinc { alias my $i = pop(@stack); my $j = $i; alias push @stack, $j; ++$i; } sub add { alias my $j = pop(@stack); alias my $i = pop(@stack); my $sum = $i + $j; alias push @stack, $sum; } { my $x=5; # $x + ++$x + $x++ alias push @stack, $x; alias push @stack, $x; preinc; add; alias push @stack, $x; postinc; add; print "$stack[-1]\n"; # 18 }

    (alias $x = $y; represents the copying of a C pointer rather than copying the actual scalar.)

Re: question 1st - undefined behaviour
by Riales (Hermit) on Sep 23, 2013 at 22:03 UTC

    I think the first and second $x would be 6 actually, due to the prepend happening on the second $x.

    Here are the steps in order:

    1. ++$x: All $x are now 6.

    2. 6 + 6 + 6

    3. $x++: All $x are now 7.

    4. $x = 18: The value from the 6 + 6 + 6 is assigned to $x.

      sorry if I making a mistake, but looks like you are wrong - why - try understand why
      my $x=5; $x=++$x + $x++ + $x; warn $x;
      return's 20.
Re: question 1st - undefined behaviour
by ikegami (Pope) on Sep 24, 2013 at 18:56 UTC

    1)$x - return's copy of object $x and then return it's value in numeric context.

    While scalar, list and void context affect what an operator returns, that's not the case for numeric, string and boolean context. They're not actually contexts as they don't affect what an operator returns.

    For example, addition imposes a scalar context on its operands, but those operands could just as easily return strings instead of numbers. The addition operator itself will convert the scalars to numbers.

    $x places that scalar on the stack. Not a copy of it.

Re: question 1st - undefined behaviour (perlop)
by Anonymous Monk on Sep 23, 2013 at 22:19 UTC
      if you talking about operators precedence, so we can calculate that expression by the next way:
      $x + ++$x + $x++:
      ++$x - ok, at now here returns 6.
      $x++ - ok, at now here return 6, but $x will right now is 7 so we must get 21, if anywhere we get $x object as is, -but it isn't so.
      we can get 19, if we get values, not objects - i've mean 7+6+6
      we will get
      5(value of copy of the object before any object changes)+7(at this position is value of original object $x)+6(at this position copy of $x after we make ++$x) == 18 - by logic which I describe.

      Let's make first other operation - $x++ not ++$x - we get 5 here anyway.
      then we make ++$x ($x == 6 ) - ok - we get 7 here. 7+5==12.
      for getting at now 18 as a result we must take $x==6 - look's like it is absolutely wrong.

      by operators precedence from perlop(at perldoc) we can say that we calculate it from left to right.
      why in position of $x - we get value of copy $x not for the moment of calculation, but for the moment of expression calculation begin.
      I've mean exactly this -
      my $x=5;
      my $y=$x + ++$x;
      $y returns 12.

      here $x in first position is used as original $x and it's returns it's changed value after calculation of pre-increment.

      my $x=5;
      my $y=$x + ++$x + $x++
      $y returns 18. precedence crash(5($x) + 7(++$x is 6, but returns $x and become 7 after next step) + 6($x++, at now $x is 7, but here we get copy before increment and get 6) in this order) or $x is used as a copy at here (like after $x++) and this copy is maked BEFORE any changes.
      my $x=5;
      my $y=++$x + $x++ + $x
      $y returns 20 -
      ++$x return $x and make it's value 6; $x++ return 6 forever, but $x is 7 at now
      7 + 6 + 7 == 20 - ok.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1055390]
Approved by marinersk
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2018-06-18 04:16 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (107 votes). Check out past polls.