Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

nested subs cause DESTROY block to not get hit

by eak (Monk)
on Aug 16, 2001 at 13:25 UTC ( #105313=perlquestion: print w/replies, xml ) Need Help??

eak has asked for the wisdom of the Perl Monks concerning the following question:

Does anyone have any idea why the DESTROY block is not hit in the following example when $foo falls out of scope? If you comment out the line in the nested subroutine, everything works as expected.
#!/usr/bin/perl -w use strict; { package Foo; $Foo::DCALLS = 0; sub new { bless {}, shift; } sub DESTROY { $Foo::DCALLS++; warn "DESTROY CALLED"; } } { my $foo = Foo->new; sub { print "FOO: $foo\n"; sub { print "FOO: $foo\n"; # comment this out and the destructor is c +alled }; }; } END { print "DCALLS: $Foo::DCALLS\n"; }

Replies are listed 'Best First'.
Re: nested subs cause DESTROY block to not get hit
by Hofmator (Curate) on Aug 16, 2001 at 14:41 UTC

    Mmhh, interesting ... well the first thing to notice is the warning perl creates about useless use of reference constructor. This indicates that you are creating a reference to an anonymous subroutine (the outer one) but actually you are doing nothing with it. The strange thing is that perl does not complain about the inner one ... I have no idea why!

    Ok, so let's change this a bit

    { my $subref; { my $foo = Foo->new; $subref = sub { # outer print "FOO: $foo\n"; }; } print "Outside!\n"; $subref->(); }
    Now perl produces no more warning because we save the (outer) anonymous sub in a variable. The destroy method is called correctly as I deleted the inner sub. The closure we created is working as expected, producing the output:
    Outside FOO: Foo=HASH(0x1a7eefc) DESTROY CALLED at xx line 15.

    In the second step we put the inner closure back in like this:

    { my $subref; { my $foo = Foo->new; $subref = sub { # outer print "FOO: $foo\n"; sub { # inner print "FOO: $foo\n"; }; }; } print "Outside\n"; $subref->(); }
    What happens now is mainly guessing on my part - so please correct me if I'm wrong. The inner closure is not handled like the outer closure by perl (e.g. no warning). It seems, perl doesn't know how to deal with these nested closures. In this case, the inner one could be completely ignored as there is no reference to the anonymous sub created and so the object could be destroyed once $foo leaves the scope. But perl wants to be on the safe side and does not destroy the object until the end of the program. That could be called a memory leak ...

    Maybe someon with more knowledge about the perl internals could shed some light on this ...

    Update: Thanks to crazyinsomniac I now see the light :) The reference to the inner anonymous subroutine is - as it is the last statement in a subroutine - implicitly returned. That's the reason why perl doesn't complain...

    -- Hofmator

Re: nested subs cause DESTROY block to not get hit
by Monky Python (Scribe) on Aug 16, 2001 at 14:42 UTC
    perls man page perltoot tells you:

    Because while a constructor is explicitly called, a destructor is not. Destruction happens automatically via Perl's garbage collection (GC) system, which is a quick but somewhat lazy reference-based GC system. To know what to call, Perl insists that the destructor be named DESTROY. Perl's notion of the right time to call a destructor is not well-defined currently, which is why your destructors should not rely on when they are called.

    and also ;)

    in really good object-oriented programming languages, the user doesn't care when the destructor is called. It just happens when it's supposed to. In low-level languages without any GC at all, there's no way to depend on this happening at the right time, so the programmer must explicitly call the destructor to clean up memory and state, crossing their fingers that it's the right time to do so. Unlike C++, an object destructor is nearly never needed in Perl, and even when it is, explicit invocation is uncalled for. In the case of our Person class, we don't need a destructor because Perl takes care of simple matters like memory deallocation.

    MP

      Unlike C++, an object destructor is nearly never needed in Perl, and even when it is, explicit invocation is uncalled for. In the case of our Person class, we don't need a destructor because Perl takes care of simple matters like memory deallocation.
      I quite disagree. GC is great for memory, but doesn't do a thing for other resources such as window handles. If an object represents a window, the object being destructed closes the window. Do you want the window to stay visible until the system notices it can collect it, or promptly when the last reference is dropped?

        hmmm... but I also don't want to destruct the object just to close the window.
        IMHO the destructor of the object should call the destroy/close function of the window and thats it....
        but it seems we are getting of topic ,)

        MP

Re: nested subs cause DESTROY block to not get hit
by bikeNomad (Priest) on Aug 16, 2001 at 21:12 UTC
    In a prior node about GC, it was mentioned that closures aren't collected properly. You're constructing a (nested) closure there; perhaps this is what is getting in your way.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://105313]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (2)
As of 2022-01-28 22:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:












    Results (74 votes). Check out past polls.

    Notices?