Timely DESTROY as a way to cleanup 
Author Message
 Timely DESTROY as a way to cleanup

I am a newbie at Perl (though becoming less and less by the frustrating
minute).

In the C++ world I often create simple stack objects that take a handle to a
resource (such as a file handle) and is released by the destructor whenever
the object goes out of scope. This typically happens by falling through the
end-brace, a return statement somewhere in the block, throw, or an
exception. Since the destructor is guaranteed to be called, I am always
assured that the encapsulated resource is properly released.

In Perl, my understanding is that the DESTROY method is called when the
reference count goes to 0. My questions are:

1) Is the DESTROY method called immediately upon leaving the block or is it
potentially delayed (as in Java where it happens when the garbage collector
gets to it)? [my expectation/hope is that it is immediate].

2) Is the DESTROY method called under all possible exits from the block
(return statement, exceptions, die, ...)? [my expectation hope is: yes]

In my case, I have a global object which coordinates logging of messages to
file. It has two relevant methods:
    1) Open - returns a file handle for 'print' calls
    2) Close - which closes the open file handle

I want to eliminate the call to 'Close' (given that laziness appears to be a
Perl virtue).

my initial code was:

    package Pkg;
        ...
        sub Open
        {    open MYFILE ">>filename" or return undef;
             return *MYFILE;
        }

    in the caller I was:

        {
            ... some code...
            my $fd = Pkg::Open or die ...;    # method keeps track of the
handle

            ... bunch of print statements....
            Pkg::Close();        # all this method does is close the handle
        }

Mark-Jason Dominus was kind enough to point out to me that I could eliminate
the call to 'Close' by changing the 'Open MYFILE' to use IO::Handle (or
IO::File). His reasoning is that the reference count on $fd in the above
code doesn't go to zero because the file handle is still reachable through
*MYFILE.

I would like to confirm my understanding of what really happens: The
'return' statement increases the reference count (from 1 to 2). When MYFILE
goes out of scope the reference count decrements (from 2 to 1) [and it has
to be in this order otherwise if the decrementing is done first, it would
reach zero and be DESTROYed before it can be incremented back to 1]. This
means that the caller's $fd has the only reference. When it goes out of
scope, the DESTROY should be called.

If the above is true than the code below is actually equivalent (but
simpler)... is that correct?

The code becomes

    package Pkg;
        ...
        sub Open
        {   my $fd = IO::File->new(...filename...);
             return $fd or die ...;
        }

    in the caller:

        {
            ... some code...
            my $fd = Pkg::Open or die

            ... bunch of print statements....
        }

My last question (as a newbie): Is this the proper way to do this in Perl?

-TIA
David



Mon, 08 Sep 2003 10:25:17 GMT  
 Timely DESTROY as a way to cleanup

Quote:
> 1) Is the DESTROY method called immediately upon leaving the block or is it
> potentially delayed (as in Java where it happens when the garbage collector
> gets to it)? [my expectation/hope is that it is immediate].

At present it's called immediately, but this is not guaranteed for the
future.  There's some chance that in the future the garbage collection
strategy might be changed.

Quote:
> 2) Is the DESTROY method called under all possible exits from the block
> (return statement, exceptions, die, ...)? [my expectation hope is: yes]

It should be.  If not, that is a bug.


Mon, 08 Sep 2003 11:25:19 GMT  
 Timely DESTROY as a way to cleanup

Quote:

> > 1) Is the DESTROY method called immediately upon leaving the block or is
it
> > potentially delayed (as in Java where it happens when the garbage
collector
> > gets to it)? [my expectation/hope is that it is immediate].

> At present it's called immediately, but this is not guaranteed for the
> future.  There's some chance that in the future the garbage collection
> strategy might be changed.

If the 'immediacy' of the DESTROY method is subject to change in future
releases of Perl, how can I code objects which will release their internal
resources as soon as they go out of scope?

Seems to me that in my case the only choice I have is to explicitly code the
call to 'close ($fd)' before exiting scope. This it a major pain since I
have to find all exit paths from scope and make sure they contain an
explicit call to release resource. This is actually more messy than it
sounds since I have to capture any exceptions (die, carp, ...) etc.) in any
nested calls from the scope.

I guess my vote (for all its worth) is to guarantee that DESTROY is called
immediately in all future versions of Perl, even if DESTROY and GC happen at
two different times (DESTROY immediately, GC when Perl gets around to it).
Otherwise I would expect a fair number of legacy applications to break.

-Regards
David



Mon, 08 Sep 2003 20:39:24 GMT  
 Timely DESTROY as a way to cleanup

Quote:
> > 1) Is the DESTROY method called immediately upon leaving the block or is it
> > potentially delayed (as in Java where it happens when the garbage collector
> > gets to it)? [my expectation/hope is that it is immediate].

> At present it's called immediately, but this is not guaranteed for the
> future.

Really?  I would be seriously upset if this were to change.  It would
break a _lot_ of code.

I often see/write code that relies on the assumption that, for
example, a IO::Handle object going out of scope will immediately flush
buffers and close the file desciptor.

perlob clearly states:

       When the last reference to an object goes away, the object
       is automatically destroyed.  (This may even be after you
       exit, if you've stored references in global variables.)
       If you want to capture control just before the object is
       freed, you may define a DESTROY method in your class.  It
       will automatically be called at the appropriate moment,
       and you can do any extra cleanup you need to do.

Note the first word of that paragraph is "when" not "after".  (It does
not however say "only when").

Of course, "last reference" should now read "last non-weakened
reference".

Quote:
> There's some chance that in the future the garbage collection
> strategy might be changed.

I hope and believe that any future GC change will only effect the
destruction of cyclic structures that haven't weakened their
self-references.

In the following code in 5.6 FOO::DESTROY is called after the END
block.  In future versions it may get called at an indeterminate time
after $x goes out of scope.

sub FOO::DESTROY { print "FOO::DESTROY called\n"; }

END { print "Begin global destruction phase\n"; }

{
  my $x;
  $x = bless [ \$x, 1 .. 10000 ], 'FOO';
  print "\$x goes out of scope\n";

Quote:
}

print "Do something that allocates a lot of memory\n";

--
     \\   ( )
  .  _\\__[oo

 .  l___\\
  # ll  l\\
 ###LL  LL\\



Tue, 09 Sep 2003 01:52:50 GMT  
 Timely DESTROY as a way to cleanup



Quote:

> I guess my vote (for all its worth) is to guarantee that DESTROY is called
> immediately in all future versions of Perl, even if DESTROY and GC happen
at
> two different times (DESTROY immediately, GC when Perl gets around to it).
> Otherwise I would expect a fair number of legacy applications to break.

I agree with David, the current implementation of DESTROY, in which the
method is called as soon as the last reference to the object is gone, is
good. Furthermore I know that tons of my code is going to break, if this
behaviour is going to change in the future.

If the eminent designers of Perl are contemplating to change this behaviour,
may I suggest that they implement an additional call during the garbage
collection?



Mon, 08 Sep 2003 22:01:29 GMT  
 
 [ 5 post ] 

 Relevant Pages 

1. ADO Access

2. DESTROY not destroying

3. Puzzle: DESTROY not destroying

4. destroy and DESTROY in Tk/Perl

5. Perl cleanup/style question (packages, libraries, namespaces)

6. Order of cleanup when perl exits

7. Perl .newsrc cleanup script?

8. Suspend trapping and cleanup before suspending (HOW)?

9. Memory usage/cleanup & hashes

10. catching signals for cleanup

11. Cleanup ASCII version of Word-Processed Doc?

12. Apache::Session cleanup??

 

 
Powered by phpBB® Forum Software