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

Can you think of a way to guarantee that Perl does not unload a class module *before* it deletes the final instance of this class? I have written a Perl object module that contains a database connection class variable (it is a package variable). The class constructor counts each object instance, and creates a database connection only for the first object instance. The destructor disconnects from the database only when Perl deletes the *last* instance. However, when the DESTROY method, on behalf of the final instance, attempts to disconnect from the database, Perl complains that the database reference is no longer defined! By having the END subroutine defined in this module print out a debug message, I learned that Perl unloads the module *before* it deletes the the final object instance. This prematurely deletes the database connection and renders the database package variable undefined. I have avoided this issue by using the END subroutine to disconnect from the database, but it surprises me that Perl would unload a class module before it deletes all instances of a class. Do you agree that this seems like incorrect behaviour?
  • Comment on Weird perl behavior regarding unloading class modules

Replies are listed 'Best First'.
(tye)Re: Weird perl behavior regarding unloading class modules
by tye (Sage) on Jan 20, 2001 at 00:37 UTC

    Can you reproduce the problem using a very small amount of code and post that? I'm not sure I understand what you are describing.

    Anyway, Perl's global variables are not destroyed in an orderly fashion, so it might help to no store any objects in global variables.

    I'll see if I can dig up some old code of mine that demonstrates the problem (or you can www.deja.com to search comp.lang.perl.* for it yourself if you like).

            - tye (but my friends call me "Tye")
Re: Weird perl behavior regarding unloading class modules
by MeowChow (Vicar) on Jan 20, 2001 at 09:48 UTC
    Hmm, are you referring to the following behaviour:
    use strict; use warnings; package Foo; our $Obj = Foo->new(); sub new { bless {}, shift; } sub DESTROY { my $this = shift; print "DESTROYING $this\n"; } sub END { print "Ending! (global = $Obj)\n"; } ## OUTPUTS Ending! (global = Foo=HASH(0x1a7f0c8)) DESTROYING Foo=HASH(0x1a7f0c8)
    Odd indeed, that DESTOY would be called after END. These problems can usually be solved by explicitly undefing your instance object.

      Depends whether you want to be able to use your global objects from within your END block or not, eh? This was argued back and forth on p5p quite a bit, I think.

      I prefer to code like this:

      #!/usr/bin/perl -w use strict; # use other modules here # global variables here exit( main( @ARGV ) ); # subroutines here sub main { my $object= Widget::->new(); # more code here return 0; }
      so that I don't have an objects in global variables and I don't have to remember to undef things.

      A much worse problem, IMHO, is that once you get into the global destruction phase, objects are destroyed in some arbitrary order so that Z can be destroyed before X even if X holds a reference to Z. This means that X's destructor may find undef where it expects a reference to Z. This really sucks to me.

              - tye (but my friends call me "Tye")
        exit( main( @ARGV ) ); sub main { ...
        That's a C-ish brogue if ever I've heard one :)
Re: Weird perl behavior regarding unloading class modules
by ambiguous (Novice) on Jan 20, 2001 at 04:01 UTC
    This isn't a direct answer to your problem.
    What I would suggest is that you separate the database
    connection into another package. That way in the constructor
    for the current class, you would call a method in your new
    DB package. It would check to see if there is already a
    connection to the database for the calling package type.
    If not it would create one and return it.

    This way the DB class would have its own DESTROY method
    which would only get called whenever the *last* instance of the
    package that called it is destroyed.

    Just a thought.

    "Against one that is insane, insane measures are often best."