# Recursion and \$ variables

#### Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on

It appears that new \$ 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

## Re: Recursion and \$ variables

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

Ben

## Re: Recursion and \$ variables

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

## Re: Recursion and \$ variables

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.

--
Charles DeRykus

## Re: Recursion and \$ variables

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=3D'a';
for (1..2){
print \$s=3D~/(.)/ ? "match:\$1" : "no match:\$1";
\$s=3Dsubstr(\$s,1);
}
__END__

match:a
no match:a

--
Charles DeRykus

## Re: Recursion and \$ variables

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.

--
Charles DeRykus

## Re: Recursion and \$ variables

No. I need to rethink that...

--
Charles DeRykus

## Re: Recursion and \$ variables

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

## Re: Recursion and \$ variables

On Fri, 14 Aug 2009 18:30:51 -0700, sln@netherlands.com wrote:

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

## Re: Recursion and \$ variables

sln@netherlands.com wrote:

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

## Re: Recursion and \$ variables

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";

}