I am having trouble getting one of my modules to compile with what looks a variable scoping issue, but I don't understand why.
Sample Code:
PATH: foreach my $path (@paths) {
open(my $file, '<', $path) or next PATH;
my %properties;
LINE: while (<$file>) {
$_ =~ /$property_regex/ or next LINE;
$properties{$1} = $2;
}
foreach (@property_keys) {
unless ($properties{$_}) {
# do stuff
next PATH;
}
if ( $irrelevant_condition ) {
# do stuff
next PATH;
}
foreach my $new_var (@new_list) {
# do stuff (does not iterate PATH loop)
}
} continue {
if (defined $file) { close($file) or die; }
}
Translated to the stripped down code above, the error I'm getting is:
Global symbol "$file" requires explicit package name at line 25
Namely, it seems to be complaining about the use of $file in the continue block at the bottom. As you can see, $file is declared as a lexical variable on line 2, within the outer foreach loop (labelled PATH).
However, based on the perldoc for continue, I would expect $file to still be in scope:
[...] 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 [...]
In order to be able to increment a loop variable, wouldn't the continue block have be treated as part of the same lexical scope as the loop to which it is attached?
What am I missing?
Note: This module is a Moo class, so while I do not have an explicit use strict statement anywhere, when you use Moo we enable strict and warnings.
Your $path variable is still in scope inside the continue BLOCK, but the stuff inside for's BLOCK is out of scope because you've reached the end of that BLOCK (you've hit the end brace / exited the braces). The $path variable, however, is not inside the braces, so can be visible inside the continue BLOCK (even though it's not visible beyond that).
If the syntax were like this:
for (...)
{
$x = stuff();
continue { more_stuff($x) }
}
then I would expect $x to be visible. IIRC, perl 6 has stuff like this, but in perl 5, the continue BLOCK is outside the loop's block, and thus doesn't see lexical variables inside that block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With