http://www.perlmonks.org?node_id=85351


in reply to For loop problem

You're looking at execution order for the '..' operator:
++$. .. $.++ . $.
There's no guarantee as to which operand of the operator gets evaluated first. In this case, it appears to be the RHS ($.++ . $.). So you get '12', but you leave $. at 2. Then the loop happens.

Replies are listed 'Best First'.
Re: Re: For loop problem
by srawls (Friar) on Jun 03, 2001 at 22:56 UTC
    Ok, thanks bikeNomad, that does make sense. What I'm still confused at, though, is how the interperter decides the order it evaluates in. Here are a few test cases:
    for(++$....$..$.)
    When I use this is evaluates the left side first, and cycles through 1 to 11.
    for(++$....$.++.$.)
    But as soon as I add that second ++, it evaluates the right side first, and cyles through 2 to 12.
    for(++$....$..++$.)
    And this is perhaps the strangest of them all. It evaluates the right side of the ...(flip flop) operator first, and also evaluates the right side of the .(concatanation) operator first. It cycles through 2 to 22.

    The 15 year old, freshman programmer,
    Stephen Rawls
      The problem is that the list ($a .. ++$a) is not evaluating a list like you think it is. It is not doing:
      $start = $a; $end = ++$a; for ($_ = $start; $_ <= $end; $_++) { ... }
      But rather, it is evaluating its endpoints, and then constructing the list from that. That is the cause of your problem:
      for (++$x .. $x++ . $x) { ... } # starting at ++$x # ending at $x++ . $x # THE END HAS MODIFIED THE START
      You can witness a similar result from:
      print ++$x, ++$x, ++$x; # 333
      You see, the arguments to a function aren't copies of the variables, but rather aliases -- by modifying ONE of the $x's, you've modified the others as well.

      Knowing this, the output of this program makes sense to me:

      $x = 3; print ++$x/$x--; # 3/4 => 0.75
      Why is that? Well, the numerator is ++$x, and the denominator is $x--; but in subtracting 1 from $x in the denominator, we have now altered the numerator back to its original state!

      I've worked out a solution to your 1 .. 12 loop, then.

      for (++$x .. $x++ . $x--) { ... } # or for (++$....$.++.$.--) { ... }
      See if you can work out why the starting point is 1.

      japhy -- Perl and Regex Hacker
        print ++$x, ++$x, ++$x; #333 print ++$x, $x++, ++$x; #313

        Given a left to right evaluation, to me this should produce 123 and 113 respectively.

        "You see, the arguments to a function aren't copies of the variables, but rather aliases -- by modifying ONE of the $x's, you've modified the others as well"

        I can accept that but what about this:
        my $x=3; print $x, $x=5, ++$x, $x--, $x, $x++, $x=0; #0006050 print $x++, $x=5, ++$x, $x--, $x, $x++, $x=0; #3006050

        Again, 3566550 seems the reasonable output (to me) for both accounts. Instead the post-(in|de)crement operators seem to be squireling away their value of $x when it came by them in a left to right evaluation of the terms.

        I can see the pattern and work with it, my question is why is it that way? What are the advantages to this type of evaluation? I don't know enough Perl to extrapolate the reasoning behind them.

        As one final example consider:
        $x = 3; print ++$x/$x--;

        Coming into the function x is 3, it gets pre-incremented (now 4), it's divided by x (still 4), x is post-decremented (to 3). Print outputs 1 (4/4) and x leaving the function is 3. This is how it _should_ happen to my mind, instead it's 3/4 as stated earlier.

        Maybe it's just my logic that's skewed or I'm showing a glaring flaw in my understanding of how operations need to work internally, but it seems rather convoluted for no good reason.

        -- I seek enlightenment