in reply to Reference to guard not released

You created a block of code, called a “closure,” which references a variable outside itself and which therefore seizes a reference-count to that data object.   The subroutine itself is never called, but it nevertheless exists. It is built at compile time.   Even though it is dead-code, Perl generates it anyway.

You can confirm my assertion that the sub is never called by this one-liner:
perl -e 'sub { print "foo!\n"; }'
... which produces no output.

Replies are listed 'Best First'.
Re^2: Reference to guard not released
by roman (Monk) on Jul 18, 2012 at 16:33 UTC

    Which subroutine is never called? The one which is the last command in do block and which is thus stored in $code? It is called explicitly right after do block - (see $code->())

    my $code = do { my $g; sub { $g = Scope::Guard->new( sub { warn "destroyed"; $x ; } ); } }; $code->();
      So what is ScopeGuard supposed to be guarding? "$x"?

      You declared $x at the global level. Is that what you are protecting? That doesn't get destroyed until the program exits...

      You declared an anonymous sub inside scopeguardnew... that's also unlikely to be destroyed until your program exits -- because Scope::Guard is holding a "reference" to the interior sub (likely)... and, AT THE LEAST, the 'my $x' is declared at the global level -- so it won't be destroyed until the prog exits...

      But I checked, and putting braces around the dcl of $x, doesn't change the output. So I would bet scopeguard has stored a reference to the interior sub so it can be called when "$x" goes out of scope.

      But you referenced "$x" in side the sub that scope guard stored...--- so $x can't go out of scope until the interior sub (that you passed to SG->new) disappears -- and it won't disappear until your prog exits...

      All you did by assigning undef to $code is lose the reference to the outside sub.. SGnew still has a reference to the inner sub and $x...

      The reference to $x, that is in the anonymous sub, is referred to in jargon, as a "closure".

      I'd guess that's because it creates a closed "ecosystem" that holds the anon-sub and the anon-sub's copy of $x -- no one changing '$x', after that sub is defined, will affect the value that is stored (referenced, really), in that inner sub (inside the new)...

      Does that make more sense?

        I don't want to protect $x. I just want to touch $x (store the value into it) when Scope::Guard object gets destroyed, i.e. when all references to it go out of scope.

        In simple and obvious example below, the $g gets destroyed and inner sub called immediately after it goes out of scope.

        use strict; use Scope::Guard; my $x; { my $g = Scope::Guard->new(sub {$x; warn "destroyed"}); } warn "end";
        But I checked, and putting braces around the dcl of $x, doesn't change the output. So I would bet scopeguard has stored a reference to the interior sub so it can be called when "$x" goes out of scope.

        Your bet is wrong. The sub is called the guard gets destroyed, not the object it references. Look at the Scope::Guard code. Is very short and self explanatory.

        All you did by assigning undef to $code is lose the reference to the outside sub.. SGnew still has a reference to the inner sub and $x...

        Yes, but when I lose reference to the outside sub, I should also lose the last reference to $g, because the sub is the only object which sees $g. But it doesnot happen.

        Does that make more sense?

        I need to read comments above, but it still doesnot make more sense to me. However constructed is the inner sub (stored in $g) it is just another object referenced by $g, not referencing it. So I don't understand how it (the inner sub) can affect the reference count to $g.

        The example I gave doesnot make sense itself, it is just the simplest demonstration of the behaviour I was able to make up. My original was more like the test below: ($x is \@res, I just try to log into res, when the object gets destroyed).

        use strict; use Test::More tests=>2; use Scope::Guard; sub try { my @res; my @subs = do { my $g; ( sub { push @res, 'a'; $g = Scope::Guard->new( sub { warn "destroyed"; push @res, 'destroyed' } ); }, sub { push @res, 'b'; undef $g; } ); }; ( shift @subs )->(); is_deeply( \@res, ['a'] ); undef @subs; is_deeply( \@res, [ 'a', 'destroyed' ] ); } try();
        You are missing the point of what Scope::Guard is. Scope::Guard is not for guarding variables and it does not store any references beside the closure. But the closure does keep references. See my other answer.