Recursion and ${*digit*} variables

Discussion in 'Perl Misc' started by Mark, Aug 14, 2009.

  1. Mark

    Mark Guest

    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
    Mark, Aug 14, 2009
    #1
    1. Advertising

  2. Mark

    C.DeRykus Guest

    On Aug 14, 11:49 am, Mark <> wrote:
    > 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

    --
    Charles DeRykus
    C.DeRykus, Aug 14, 2009
    #2
    1. Advertising

  3. Mark

    Mark Guest


    > 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
    Mark, Aug 15, 2009
    #3
  4. Mark

    C.DeRykus Guest

    On Aug 14, 2:46 pm, "C.DeRykus" <> wrote:
    > On Aug 14, 11:49 am, Mark <> wrote:
    >
    >
    >
    > > 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



    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
    C.DeRykus, Aug 15, 2009
    #4
  5. Mark

    C.DeRykus Guest

    On Aug 14, 4:17 pm, "C.DeRykus" <> wrote:
    > On Aug 14, 2:46 pm, "C.DeRykus" <> wrote:
    >
    >
    >
    > > On Aug 14, 11:49 am, Mark <> wrote:

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

    >
    > 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...

    --
    Charles DeRykus
    C.DeRykus, Aug 15, 2009
    #5
  6. Mark

    C.DeRykus Guest

    On Aug 14, 4:10 pm, Mark <> wrote:
    > > 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


    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
    C.DeRykus, Aug 15, 2009
    #6
  7. Mark

    Guest

    On Fri, 14 Aug 2009 11:49:39 -0700 (PDT), Mark <> wrote:

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

    }
    , Aug 15, 2009
    #7
  8. Mark

    Guest

    On Fri, 14 Aug 2009 16:17:32 -0700 (PDT), "C.DeRykus" <> wrote:

    >On Aug 14, 2:46 pm, "C.DeRykus" <> wrote:
    >> On Aug 14, 11:49 am, Mark <> wrote:
    >>
    >>
    >>
    >> > 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

    >
    >
    >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
    , Aug 15, 2009
    #8
  9. Mark

    Guest

    On Fri, 14 Aug 2009 18:30:51 -0700, wrote:

    >On Fri, 14 Aug 2009 16:17:32 -0700 (PDT), "C.DeRykus" <> wrote:
    >
    >>On Aug 14, 2:46 pm, "C.DeRykus" <> wrote:
    >>> On Aug 14, 11:49 am, Mark <> wrote:
    >>>
    >>>
    >>>
    >>> > 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

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


    Aparently, for the N vars, the scope remained the same, it
    never left. Kind of makes sense.
    -sln
    , Aug 15, 2009
    #9
  10. Mark

    Nathan Keel Guest

    wrote:

    > 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.
    Nathan Keel, Aug 15, 2009
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fangs
    Replies:
    3
    Views:
    9,782
    darshana
    Oct 26, 2008
  2. Replies:
    9
    Views:
    935
  3. Eric Armstrong
    Replies:
    9
    Views:
    134
    Eric Armstrong
    Jul 22, 2006
  4. Kermit Piper
    Replies:
    17
    Views:
    423
    Dr John Stockton
    Feb 11, 2006
  5. Replies:
    8
    Views:
    734
    John Reye
    Apr 26, 2012
Loading...

Share This Page