brian_d_foy has asked for the wisdom of the Perl Monks concerning the following question:
I ran into a new question in our Learning Perl class today. A student tried to combine a previous example with the redo stuff we had just covered. I didn't see anything in Perlmonks or in Google that discussed this, but if it has please point it out to me. :)
While using a for loop, use s/// to replace a character with nothing, but remember the character. Redo the block if the character is an e. I expected this to make an infinite loop because redo would stay in the same dynamic scope, but I see that's not true in practice:
#!/usr/bin/perl use strict; use warnings; for( $_ = "fred"; s/(.)//; ) { print "I saw the character [$&]\n"; redo if $& eq 'e'; }
The output shows that it sees the e and does the redo, but when it goes through the block again, the value in $& has disappeared (which is why it isn't an infinite loop).
I saw the character [f] I saw the character [r] I saw the character [e] Use of uninitialized value in concatenation (.) or string at test line + 7. I saw the character [] Use of uninitialized value in string eq at test line 8. I saw the character [d]
Let's try it with the match operator. I see the same effect, but also notice that the value of $i is just fine.
#!/usr/bin/perl use strict; use warnings; for( my $i = 1; $i =~ m/\d/; $i++) { print "I saw [$i]\n"; redo if $& == 5; last if $i == 10; }
Output:
I saw [1] I saw [2] I saw [3] I saw [4] I saw [5] I saw [5] Use of uninitialized value in numeric eq (==) at test2 line 8. I saw [6] I saw [7] I saw [8] I saw [9] I saw [10]
perlvar says that $& is actually dynamically-scoped to the current block, but I'm also assuming that redo stays in the same scope, so I expect that shouldn't be a problem since I think that the current block should be the one that contains the for.
The string matched by the last successful pattern match (not counting any matches hidden within a BLOCK or eval() enclosed by the current BLOCK). (Mnemonic: like & in some editors.) This variable is read-only and dynamically scoped to the current BLOCK.
So, I suspected that redo was actually creating a new dynamic scope. I add another lexical variable to the test portion of the for.
#!/usr/bin/perl use strict; use warnings; for( my $i = 1; $i =~ m/\d/, my $j = $i**2; $i++) { print "I saw [$i] and [$j]\n"; redo if $& == 5; last if $i == 10; }
The output shows that redo hides the value of $j too:
Here it is without the for loop:I saw [1] and [1] I saw [2] and [4] I saw [3] and [9] I saw [4] and [16] I saw [5] and [25] Use of uninitialized value in concatenation (.) or string at test2 lin +e 7. I saw [5] and [] Use of uninitialized value in numeric eq (==) at test2 line 8.I saw [6 +] and [36] I saw [7] and [49] I saw [8] and [64] I saw [9] and [81] I saw [10] and [100]
#!/usr/bin/perl use strict; use warnings; $_ = 123; while( m/\d/g ) { print "I saw [$&]\n"; redo if $& == 1; last; }
The output shows he same effect:
So, is this the right behavior? If not, which part is not acting right? The lexical scope or redo?I saw [1] Use of uninitialized value in concatenation (.) or string at test3 lin +e 9. I saw []
|
|---|