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

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

The first of these loops is legal perl:

#! perl -slw use strict; my $i; for $i ( 0 .. 5 ) { print "$i"; } my @i; for $i[ 0 ] ( 0 .. 5 ) { print "@i"; }

The second notionally equivalent construct produces:

syntax error at C:\test\junk1.pl line 10, near "$i[" Execution of C:\test\junk1.pl aborted due to compilation errors.

Is this an absolute "can't be done" syntax error, or one of Perl's ambiguous parsing errors that can be avoided by using some syntax (like unary + or ;) to disambiguate it?


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re: Hard syntax error or disambiguable parsing? (hard)
by tye (Sage) on Jan 29, 2009 at 03:31 UTC

    See excerpts from perly.y:

    label FOR MY remember my_scalar '(' mexpr ')' mblock cont label FOR scalar '(' remember mexpr ')' mblock cont label FOR '(' remember mexpr ')' mblock cont label FOR '(' remember mnexpr ';' texpr ';' mintro mnexpr ')' my_scalar: scalar scalar : '$' indirob indirob : WORD | scalar %prec PREC_LOW | block | PRIVATEREF

    PRIVATEREF is defined in toke.c and seems of no help here. So the only hope is: '$' block.

    for ${\$i[0]} ( 1..10 ) { print @i, $/ } __END__ Not a GLOB reference at ...

    So give it a GLOB reference:

    for ${*X=\$i[0];*X} ( 1..3 ) { print "$X(@i)$/" } 1() 2() 3()

    Which runs but still doesn't do what you want.

    Update: And the "Not a GLOB reference" is probably indicative of what merlyn noted: foreach needs to know the name of the scalar variable to create for use inside of the loop (which often obscures an existing lexical or package variable of the same name either via 'my' or 'local', as documented).

    - tye        

Re: Hard syntax error or disambiguable parsing?
by merlyn (Sage) on Jan 29, 2009 at 03:18 UTC
    A foreach loop (which you've written there misspelled as "for") absolutely wants to create a new local scalar variable to refer to each of the items of the list. You can't make this part of a larger existing structure... it doesn't make sense.

      A foreach loop (which you've written there misspelled as "for")

      eh? Not only are the keywords interchangeable, but for $i ( 0 .. 5 ) is not a foreach loop as defined in perlsyn. It shares traits with both foreach loops (syntax) and for loops (purpose and efficiency).

      It's not as clear, and this is clearly a beginner, so I thought I'd bring clarity back.

      So how do you decide which keywords to use? Choosing the keyword based on syntax (looks like a list or not) is redundant. The only meaningful criteria I can think of are memory efficiency (you'd use for here) or purpose (you'd use for here).

        but for $i ( 0 .. 5 ) is not a foreach loop as defined in perlsyn.

        It's good to know that someone else around here actually reads the docs--and arrives at the same interpretation as me.

        Personally, the whole 'unavoidable implicit localisation' of for loop variables smacks of an accidental implementation bug that got post-facto ligitimisation via Marketeer Maintainenance: The re-branding of bugs as features.

        There doesn't seem to be any logical reason why an existing variable shouldn't be used (unlocalised) as the loop iterator, given that if a strictly loop scoped iterator is required, the inline-my version achieves that perfectly.

        This would allow several common uses that currently require extra steps to achieve. For example, retaining the information of how far the loop iterated if it is terminated early via last, that currently requires an extra variable and another assignment.

        If this was an explicit decision--rather than an accidental happenstance as suggested by some of the comments in the source files--then it would be good to see the reasons laid out.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        for $i ( 0 .. 5 ) is not a foreach loop

        May I ask you in what way

        for $i ( 0 .. 5 )
        and
        foreach $i ( 0 .. 5 )
        differ, according to your opinion? perlsyn says The "foreach" keyword is actually a synonym for the "for" keyword, so I don't see how you came to the idea that the for loop your mention, would not be a foreach loop. Did I miss something here?

        -- 
        Ronald Fischer <ynnor@mm.st>
      A foreach loop absolutely wants to create a new local scalar variable

      Somehow I forgot about the scoping rules within foreach, so I reread perlsyn:

      The "foreach" loop iterates over a normal list value and sets the variable VAR to be each element of the list in turn. If the variable is preceded with the keyword "my", then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with "my", it uses that variable instead of the global one, but it's still localized to the loop.

      If I understand this right, we have 4 cases:

      { foreach my $v (...) {} } # 1 { foreach $v (...) {} } # 2 { my $v; foreach $v (...) {} } # 3 { my $v; foreach my $v (...) {} } # 4
      In case 1, $v is a lexical variable where the lifetime ends with the end of the loop. In case 2, $v is in the global symbol table, but localized, in the sense we usually get by local $v;; the localization ends at the end of the loop. As for case 3, I don't really understand the text of the man page; what does localizing a lexical variable mean? As for case 4, the man page doesn't say anything explicitly, so it must be in effect the same as case 1.

      Is this correct, and could you please give some explication about case 3?

      -- 
      Ronald Fischer <ynnor@mm.st>

        Case 4 is in fact identical to case 3, since $v in both cases is already a 'my' variable, subject to lexical scoping.

        Yet again I learn...and I even read the documentation (I even went back and read what I thought was the full description of this construct). But clearly I did not.

        rovf's extract actually reminded me of what I had learned for what seems like a long time ago...the difference between my and local in the context of the loop variable. And it is the local at work that made my test code (listed in an earlier thread on this inquiry)...not because, as I mis-stated, the loop variable is automatically lexically scoped (ala, my or an implicit my).

        Thanks, rovf. Maybe someday I'll be able to keep more of Perl's wonderments straight in my mind.

        ack Albuquerque, NM
        Sure, the words are interchangable, in the same way that you can omit $_ a lot. It's not as clear, and this is clearly a beginner, so I thought I'd bring clarity back.

        As for the second statement, I don't understand your complaint. The first loop does indeed create a new local scalar variable, as I said.

Re: Hard syntax error or disambiguable parsing?
by JavaFan (Canon) on Jan 29, 2009 at 16:23 UTC
    Suppose it could be done. What should the following do:
    my @a = qw [a b c]; for $a[7] (1 .. 5) { 1; # Body not important. } say 0 + @a;

      It would operate the same as this, but without the need to re-state the loop variable 3 times:

      #! perl -slw use strict; my @a = qw [a b c]; for( $a[7] = 1; $a[ 7 ] <= 5; ++$a[7] ) { print $a[ 7 ]; } print 0 + @a; print "@a"; __END__ C:\test>junk2.pl 1 2 3 4 5 8 Use of uninitialized value in join or string at C:\test\junk2.pl line +10. Use of uninitialized value in join or string at C:\test\junk2.pl line +10. Use of uninitialized value in join or string at C:\test\junk2.pl line +10. Use of uninitialized value in join or string at C:\test\junk2.pl line +10. a b c 6

      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.