If I were to write a loop like this:
1 for ( 1 .. 3 ) { 2 my $x = $_; 3 } 4 print $x;
I would except the following to happen:
1. Each time through the loop, the lexical variable $x is declared and set to $_ (1, then 2, then 3).
2. Outside the loop, $x has never been defined, so nothing is printed.
This is what happens.
I would further expect that if I were to "use strict", the code would break at compile-time on line 4 because $x is not predeclared at the top level of lexical scope.
Again, this is what happens.
But weird stuff starts happening if I use a postfix loop:
1 my $x = $_ for ( 1 .. 3 ); 2 print $x;
This code is conceptually identical to the first example, and Deparse returns identical output.
The print statement still prints nothing, so the "my" declaration is not making a top-level lexical (i.e. a lexical variable at the top level of the package). The first $x is still restricted in scope to the body of the for-loop.
However, a "using strict" no longer catches the undeclared $x outside of the loop.
This is my guess as to what is happening: "use strict" checks for scope based on brackets, before anything is compiled; as a result the "my" statement on line 1 APPEARS to "use strict" be a top-level lexical variable to; therefore the use of the undefined $x on line 2 is not flagged by "use strict"
When the code is compiled, however, and the actual lexical rules are realized, a postfix for-loop is compiled just like a regular prefix for-loop; i.e. the code compiles like the first example. Then, the loop executes and the print statement, having no $x in scope, just creates it, set it to undef, and prints it. This is not an error because "use strict" (at least the 'vars' part of it) only is checked at compile time, so once the compile has passed, the code executes as if "use strict" had never been turned on, and as we all know from that time we forgot to turn on "use strict", having a brand new variable pop into existence is no problem at all!
Is this conclusion correct?
But this is not what happens, so now I must assume that $x is lexical to the body of the for-loop. Thus, I would expect "use strict" to flag the use of $x in the print statement, but this doesn't happen either.1 my $x; 2 $x = $_ for ( 1 .. 3 ); 3 print $x;
Is this a known bug in Perl?
Note that if you explicitly put brackets around the body of the postfix for-loop, as in:
then everything is happy: "use strict" DOES now catch the undefined $x on line 2.1 do { my $x = $_ } for ( 1 .. 3 ); 2 print $x;
And now for some REAL weirdness...
Suppose I explicitly predeclared my top-level lexical:
This doesn't work at first blush because "use warnings" complains of a duplicate declaration. If you take out "use warnings", you get really bizarre behavior.1 my $x = 6; 2 my $x = $_ for ( 1 .. 3 ); 3 print $x;
Based on my conclusion above, the first $x should be a top- level lexical, and the second $x should be a lexical with scope of the loop body, even if "use strict" doesn't think so, but the for-loop clobbers the top-level variable! it doesn't leave it set at 3, as it would if you took the "my" out of line 2; it doesn't avoid it as if you used a prefix loop, or reset it back to 6, as it would if you could substitute a "local" for the "my" on line 2.
It resets $x back to undef! What is going on NOW?
In reply to Lexical scope vs. postfix loops (perl bug?) by jh
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |