Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Global destruction feature / bug ?

by liz (Monsignor)
on Apr 03, 2008 at 13:44 UTC ( [id://678159]=perlquestion: print w/replies, xml ) Need Help??

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

This little program produces a result that was at least unexpected by me and a few other Amsterdam Perl Mongers:
use strict; use warnings; sub Foo::DESTROY{ print "object $_[0]->[0] destroyed\n"; } my $foo = bless [ 'foo' ], 'Foo'; # notice 'my' our $bar = bless [ 'bar' ], 'Foo'; # notice 'our' END { print "END block executed\n"; }
produces:
object foo destroyed END block executed object bar destroyed
What I expected was:
END block executed object foo destroyed object bar destroyed
In other words, any objects tied to file lexicals would be destroyed at global destruction *after* the execution of the END block. But apparently, they are destroyed *before* the END block executes. This seems at least the case with 5.8.1, 5.8.5, 5.8.8. and 5.10.0.

Is this behaviour documented anywhere? If not, where would be a good place to document this (as it cost me a few days wallclock to figure this one out and many people that I've asked their expectation about this piece of code, have given the wrong answer).

The reason I'm asking, is that I'm working on some leak detection utility. In this code example, I would consider both $foo as well as $bar as having leaked, as they were not reclaimed before the program ended. Having $foo being DESTROYed *before* the END block executes, just makes things so much more complicated... ;-(

Suggestions? Comments?

Liz

Replies are listed 'Best First'.
Re: Global destruction feature / bug ?
by Corion (Patriarch) on Apr 03, 2008 at 13:53 UTC

    To me, this behaviour makes sense because my $foo gets reclaimed as soon as the current scope is left (main::). After the main program has ended, the END blocks fire, and after that, all global variables get cleaned up.

    Except (as I just realize) that our is not supposed to be a global(ly visible) variable and hence should be reclaimed at the same time as my $foo, that is, in my opinion before the END blocks are run.

    One more reason to avoid our IMO.

    Update: My opinion on the order of things is wrong - the order of execution/destruction of objects is exactly as it has to be because the our variable is a global variable except that the name is not visible outside the file.

      Just to play devil's advocate . . .

      The name declared by the our isn't globally visible, but the value residing in the symbol table which it refers to is a global. The only difference is the duration of the scoping of the name you're using to access it, so it's entirely reasonable that that value is destroyed along with the normal global variable cleanup pass regardless of how you're accessing it.

      (To put it another way, you would definitely be surprised if the value in the global $main::foo was destroyed just because the temporary reference to it you created with local *somepackage::foo = \$main::foo; goes out of scope.)

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      our is not supposed to be a global(ly visible) variable and hence should be reclaimed at the same time as my $foo

      I have to disagree. our creates a lexical alias for the global variable (stored in the symbol table).

      use Devel::Peek; our $foo; Dump $foo; Dump $main::foo; __END__ SV = NULL(0x0) at 0x24bfdc4 REFCNT = 1 FLAGS = () SV = NULL(0x0) at 0x24bfdc4 REFCNT = 1 FLAGS = ()
      The alias isn't globally visible, but there's still a global variable behind it. This is how it should be. Consider this:
      use strict; { our $foo = 'foo'; our $bar = 'bar'; } { our $foo; print $foo; print $main::bar; } __END__ foobar

      lodin

      our doesn't differ significantly from use vars except that the syntax is nicer and the name is only available in the local scope even though the data is global to the namespace. I think it's well documented that our $bar doesn't go out of scope until global destruction.

      I actually think the behavior of the parent program is exactly what you should expect if you read our and my carefully.

      Please don't be down on our. It's 5.8 chic. :(

      -Paul

        It's mostly because of that why I dislike use of our - it establishes a global variable except that I cannot get at it or change it from the outside. And in most cases I've encountered, there always comes a moment where I want/need to change a global variable. For example to add or change some configuration, or change the quote indicator from " to ' or `. And our prevents me from doing that while adding no benefit...

Re: Global destruction feature / bug ?
by moritz (Cardinal) on Apr 03, 2008 at 14:00 UTC
    I can't answer your questions, but I would expect that the compiler/interpreter is free to destroy any object that isn't used anymore.

    If you use the variable $foo in the END block, it's only destroyed afterwards.

    Since lexical variables are only accessible from their scope, it's much easier for the compiler to proof that they aren't used from somewhere else anymore. our variables could still be referenced from END blocks in other packages.

    BTW perlobj says

    Since DESTROY methods can be called at unpredictable times, it is important that you localise any global variables that the method may update.

    That's a pretty bold statement that should shouldn't rely on any particular order.

Re: Global destruction feature / bug ?
by ikegami (Patriarch) on Apr 03, 2008 at 19:05 UTC

    When the scope (the file) ends, the last reference to $foo is released, so it's detroyed.

    If any function (incl END) referenced $foo, it would capture the variable. In that case, there would still be a reference to the variable at the end of the file scope, so the variable will survive until global destruction.

    use strict; use warnings; sub Foo::DESTROY{ print "object $_[0]->[0] destroyed\n"; } my $foo = bless [ 'foo' ], 'Foo'; # notice 'my' our $bar = bless [ 'bar' ], 'Foo'; # notice 'our' END { $foo; print "END block executed\n"; }
    should produce
    END block executed object foo destroyed object bar destroyed

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-03-19 10:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found