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:

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]
Here it is without the for loop:
#!/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:

I saw [1] Use of uninitialized value in concatenation (.) or string at test3 lin +e 9. I saw []
So, is this the right behavior? If not, which part is not acting right? The lexical scope or redo?
--
brian d foy <brian@stonehenge.com>
Subscribe to The Perl Review

In reply to Does redo create a new dynamic scope? by brian_d_foy

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.