Recursion and ${*digit*} variables

M

Mark

It appears that new ${*digit*} variables are not created when the same
subroutine is re-entered. Is this to be expected?

use strict ;
use warnings;

my $line = 'abc';
doit();
exit;

sub doit {
# local($1); # adding this doesn't appear to have an effect
$line =~ /(.)/ || die "no match";
print "bef \$1 =$1\n";

$line = substr($line,1);
doit() if length($line);

my $thing = $1; # WRONG! $1 has been changed by recursive call to
doit()

print "aft \$1 =$1\n";
}


Output:
bef $1 =a
bef $1 =b
bef $1 =c
aft $1 =c
aft $1 =c
aft $1 =c

Expected output:
bef $1 =a
bef $1 =b
bef $1 =c
aft $1 =c
aft $1 =b
aft $1 =a
 
C

C.DeRykus

It appears that new ${*digit*} variables are not created when the same
subroutine is re-entered.  Is this to be expected?

use strict ;
use warnings;

my $line = 'abc';
doit();
exit;

sub doit {
#   local($1);  # adding this doesn't appear to have an effect
    $line =~ /(.)/ || die "no match";
    print "bef \$1  =$1\n";

    $line = substr($line,1);
    doit() if length($line);

    my $thing = $1; # WRONG! $1 has been changed by recursive call to
doit()

    print "aft \$1  =$1\n";

}

Output:
bef $1  =a
bef $1  =b
bef $1  =c
aft $1  =c
aft $1  =c
aft $1  =c

Expected output:
bef $1  =a
bef $1  =b
bef $1  =c
aft $1  =c
aft $1  =b
aft $1  =a

No, this came up in a recent thread. Even if a match fails
within a given scope, a previously successful backref isn't
cleared:

my $s='a';
for (1..2){
print $s=~/(.)/ ? "match:$1" : "no match:$1";
$s=substr($s,1);
}
__END__

match:a
no match:a
 
M

Mark

I would expect any sub call (that performed a successful match) to
clobber $N. Is that not the case?

No, I don't believe that is the case. When I remove the recursion, it
works as I expect, the local $N retains its value.
For example:

use strict ;
use warnings;

my $line = 'abc';

doit();

exit;


sub doit {
$line =~ /(.)/ || die "no match";
print "bef1 \$1 =$1\n";

$line = substr($line,1);
doit2() if length($line);

print "aft1 \$1 =$1\n";
}


sub doit2 {
$line =~ /(.)/ || die "no match";
print "bef2 \$1 =$1\n";

$line = substr($line,1);

print "aft2 \$1 =$1\n";
}

Output:
bef1 $1 =a
bef2 $1 =b
aft2 $1 =b
aft1 $1 =a
 
C

C.DeRykus

No, this came up in a recent thread. Even if a match fails
within a given scope, a previously successful backref isn't
cleared:

my $s='a';
for (1..2){
  print $s=~/(.)/ ? "match:$1" : "no match:$1";
  $s=substr($s,1);}

__END__

match:a
no match:a


Just to expand that explanation a bit more:

sub doit {
$line =~ /(.)/ || die "no match";

print "bef \$1 =$1\n"; # matches succeed initially
$line = substr($line,1); # as $line gets emptied
doit() if length($line); # and doit() recurses
my $thing = $1; # WRONG! ..

print "aft \$1 =$1\n";
}

By the time the recursion starts to unwind, $line has
been drained and the match fails. Because the final "c"
matched successfully though, $1 doesn't get cleared.
So you see the trailing series of "c" printed.
 
C

C.DeRykus

Just to expand that explanation a bit more:

sub doit {
  $line =~ /(.)/ || die "no match";

  print "bef \$1  =$1\n";    # matches succeed initially
  $line = substr($line,1);   # as $line gets emptied
  doit() if length($line);   # and doit() recurses
  my $thing = $1; # WRONG! ..

  print "aft \$1  =$1\n";

}

By the time the recursion starts to unwind, $line has
been drained and the match fails. Because the final "c"
matched successfully though, $1 doesn't get cleared.
So you see the trailing series of "c" printed.

No. I need to rethink that...
 
C

C.DeRykus

No, I don't believe that is the case.  When I remove the recursion, it
works as I expect, the local $N retains its value.
For example:

use strict ;
use warnings;

my $line = 'abc';

doit();

exit;

sub doit {
    $line =~ /(.)/ || die "no match";
    print "bef1 \$1  =$1\n";

    $line = substr($line,1);
    doit2() if length($line);

    print "aft1 \$1  =$1\n";

}

sub doit2 {
    $line =~ /(.)/ || die "no match";
    print "bef2 \$1  =$1\n";

    $line = substr($line,1);

    print "aft2 \$1  =$1\n";

}

Output:
bef1 $1  =a
bef2 $1  =b
aft2 $1  =b
aft1 $1  =a

Hopefully I'm not mis-firing again but doit2() would introduce
a new scope with its own set of $N matches which won't be affected
by successful matches in other scopes. But in doit()'s scope,
successful $N matches self-clobber as mentioned.
 
S

sln

It appears that new ${*digit*} variables are not created when the same
subroutine is re-entered. Is this to be expected?

use strict ;
use warnings;

my $line = 'abc';
doit();
exit;

sub doit {
# local($1); # adding this doesn't appear to have an effect
$line =~ /(.)/ || die "no match";
print "bef \$1 =$1\n";

$line = substr($line,1);
doit() if length($line);

my $thing = $1; # WRONG! $1 has been changed by recursive call to
doit()

print "aft \$1 =$1\n";
}


Output:
bef $1 =a
bef $1 =b
bef $1 =c
aft $1 =c
aft $1 =c
aft $1 =c

Expected output:
bef $1 =a
bef $1 =b
bef $1 =c
aft $1 =c
aft $1 =b
aft $1 =a


Apparently there is only 1 set of N vars per scope,
looks like its set at compile time.

So you can't stack them in the way of a recursion.
This seems to hold down memory consumption and the cost
of state.

Usually, when you recurse a function, everything starts a new.
A new regular expression evaluation and gleaning results.
In that scope, the last N vars are retained, the results aren't
stacked.

The results you obtained are not faulty, nor the result of a bad match.
The last state of N vars were retained when the stack unwound.

Remember, 1 scope, 1 set of N vars.
Poor example follows.

-sln

======================================================
Output:

sub b - before = b
sub c - before = c
sub d - before = d
sub e - before = e(e)
sub d - before = d
sub e - before = f(f)
sub d - before = d
sub e - before = g(g)
sub d - before = d
sub e - before = h(h)

sub e - after = h(h)
sub d - after = d
sub e - after = h(g)
sub d - after = d
sub e - after = h(f)
sub d - after = d
sub e - after = h(e)
sub d - after = d
sub c - after = c
sub b - after = b

========================================================

use strict ;
use warnings;
my $cnt = 0;


my $regx = qr/(.)/;

$cnt = 0;
my $Estr = 'e';
b();


sub b
{
my $str = 'b';
$str =~ /$regx/;
print "sub b - before = $1\n";
c();
print "sub b - after = $1\n";
}

sub c
{
my $str = 'c';
$str =~ /$regx/;
print "sub c - before = $1\n";
d();
print "sub c - after = $1\n";
}

sub d
{
my $str = 'd';
$str =~ /$regx/;
print "sub d - before = $1\n";
e();
print "sub d - after = $1\n";
}

sub e
{
++$Estr if (++$cnt > 1);

$Estr =~ /$regx/;
my $tmp = $1;

print "sub e - before = $1($tmp)\n";

print "\n" if ($cnt >= 4);
d() if ($cnt < 4);
print "sub e - after = $1($tmp)\n";

}
 
S

sln

Just to expand that explanation a bit more:

sub doit {
$line =~ /(.)/ || die "no match";

print "bef \$1 =$1\n"; # matches succeed initially
$line = substr($line,1); # as $line gets emptied
doit() if length($line); # and doit() recurses
my $thing = $1; # WRONG! ..

print "aft \$1 =$1\n";
}

By the time the recursion starts to unwind, $line has
been drained and the match fails. Because the final "c"
matched successfully though, $1 doesn't get cleared.
So you see the trailing series of "c" printed.

Matching had nothing to do with why his $1 contained 'c'
when the stack unwound.

The reason is he keeps reenterring the same scope block.
In terms of N vars, there is only one scope block so
the N vars keep thier last state.

N var state is not stacked, it only has scope.

-sln
 
S

sln

Matching had nothing to do with why his $1 contained 'c'
when the stack unwound.

The reason is he keeps reenterring the same scope block.
In terms of N vars, there is only one scope block so
the N vars keep thier last state.

N var state is not stacked, it only has scope.

-sln

Aparently, for the N vars, the scope remained the same, it
never left. Kind of makes sense.
-sln
 
N

Nathan Keel

Aparently, for the N vars, the scope remained the same, it
never left. Kind of makes sense.
-sln

Apparently you forgot how to snip huge quotes for a few word reply.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top