eduardo has asked for the wisdom of the Perl Monks concerning the following question:

if you enter code that looks like:
#!/usr/bin/perl -w use strict; for (my $i = 0; $i < 10; $i++) { print "$i\n"; }
and you run it by perl -MO=Deparse, it turns into:
my $i = 0; while ($i < 10) { print "$i\n"; } continue { ++$i }
so, my question is... what is going on there! what is this continue, where is it coming from, why does it decide to parse into this structure? I guess, my question is, why is it doing this, and what am I to learn from it?

Replies are listed 'Best First'.
RE: why does a for loop parse like this?
by Russ (Deacon) on Jul 19, 2000 at 07:48 UTC
    This is fundamentally what a for loop does. It initializes in some way (usually a variable) and loops while a certain condition is true, performing some action after each time through the loop.

    Here are some benchmark results to peruse...

    Benchmark: timing 100000 iterations of Deparses, for... Deparsed: 5 wallclock secs ( 4.43 usr + 0.00 sys = 4.43 CPU) for: 6 wallclock secs ( 4.39 usr + 0.00 sys = 4.39 CPU)
    Not too surprising (in fact, I would have been shocked had there really been a substantial difference).

    Just thinking of really low-level code, the Deparse version is really just the "under-the-hood" action of a for loop. Think about assembly (pseudo) code:

    # Warning: I make no claims to know assembly, this is an example only +:-) mov bx 0 ; Initialize our loop variable mov ax, 10 ; Remember our exit condition top: ; Mark the top of the loop jnle last: ; Quit if bx is not less than ax print bx ; Do the body of the loop add bx 1 ; Add one to the loop variable jmp top: ; go to the top of the loop last:
    So, the Deparsed code is just a closer representation of the low-level code.

    The continue block (from perlsyn)

    If there is a continue BLOCK, it is always executed just before the conditional is about to be evaluated again, just like the third part of a for loop in C. Thus it can be used to increment a loop variable, even when the loop has been continued via the next statement (which is similar to the C continue statement).
    So, the continue block executes once per iteration of the loop. Why would you use one yourself?
    • Maybe you want a complex "once-per-loop" construct which would be too obfuscated as part of the normal for construct.
    • Maybe you want multiple exit points from the body of your loop. You don't want to write the once-per-loop over and over (once per exit point), so put it in a continue, and just use next when you need to exit.
    • Maybe you really embrace TMTOWTDI

    Russ
    Brainbench 'Most Valuable Professional' for Perl

      i understand that much... i guess what is confusing to me, is the fact that the parser changes all for loops into while loops with some sort of "post loop modifier" called continue... what I really don't understand is, why was the design desicion made to deal with this in this way? is this the way all languanges handle "C style for constructs?" 'cause if it is, that's really a VERY interesting little bit of information to keep in the very back of my head...
        To quote Nikolaus Wirth on this one: the "for" loop is just syntactic sugar. There is no need for the different type of loops, they are just nice to look at (i.e. you can rewrite every loop using anoother one). That's why Oberon (successor of Modula 2, successor of Pascal) doesn't have a "for" statement.

        The reason why "for" is handled by rewriting it to a "while" construct: well, reuse, I guess. Since all loops are in essence equivalent, you choose one which is easy to implement and transform the others on the fly. Compiler gurus, your call ;-)

        Andreas

RE: why does a for loop parse like this?
by Adam (Vicar) on Jul 19, 2000 at 22:26 UTC
    Because Perl doesn't actually have "for". For and Foreach are synonyms which have been overloaded with the C style for loop. The deparser converts this to the while loop because that is what it really is. If you use for to process an array, the deparser happily converts it to foreach.
    E:\>perl -MO=Deparse -e "for( [1..10] ){ print $_ }" foreach $_ ([(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]) { print $_; } -e syntax OK