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


in reply to Re: Re: For loop problem
in thread For loop problem

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

Replies are listed 'Best First'.
Re: Re: Re: Re: For loop problem
by Arguile (Hermit) on Jun 04, 2001 at 00:26 UTC
    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
      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.
      Post-increment and -decrement have to squirrel away their value of $x, because they change the value of $x in place but return the previous value.

      Pre-increment and -decrement, on the other hand, change the value of $x in place and then return the new value. Returning a pointer to the location of $x, rather than to a copy of the value in $x, is an optimization.

      $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.
      You appear to have the order of evaluation all wrong. The operands to /, this case ++$x and $x--, must both be evaluated before the division. What you describe sounds more like: (++$x/$x)-- except, of course, that it's a syntax error.

      By the way, you'll see the same results with other operations that modify variables in place, such as +=. print $x, $x += 1; Creating a separate copy of every value in every variable, to prevent such effects, would cost a lot in execution time and memory usage. It could also get very complicated with constructions like this: print +(($x+=1)+=1) + ($x+=$x++);

        "You appear to have the order of evaluation all wrong."

        Sorry, I should have been more precise. What I was emphasising was that $x-- was still 4 (as it returned the previous value), not that it didn't occur before the division.

        Thanks for pointing out the pointers {g}. I understood the refference passing, I was just getting hung up on left to right evaluation as if it were a stream; not the line completely evaluated, then all the pointer calls.