You can't know. Time to rethink your algorithm. The final DESTROYs happen in memory allocation order, nothing you can control.
-- Randal L. Schwartz, Perl hacker | [reply] |
Have the Util object keep a reference to the FTPSession
object (naturally, since it needs info from that object).
Have the Util destructor write to STDOUT. Then you'll
know that the FTPSession object still exists at that point.
Note that this won't work if you store your objects in
global variables nor if the script exits unexpectedly.
You want the destructors to fire when "sub main" returns,
right before "exit" is called. If the destructors fire
during "global destruction", then the order of execution
is out of your control.
#!/usr/bin/perl -w
use strict;
use FTPSession;
use Util;
exit main();
[...]
sub main {
my $ftp= FTPSession->new(...);
my $util= Util->new( $ftp );
[...]
return 0;
}
-
tye
(but my friends call me "Tye") | [reply] [d/l] |
Well, I dont know about this. I mean, the problem is this,
we have a FTPSession class as base class for
FTPSession::Win32 and FTPSession::Unix and of course the
means of FTP'ing is done in Win32::Internet in the former
and Net::FTP for the latter.
We have another package, Util, in which we build up a
string version of the log message we output to STDOUT.
To save from the client having to tell us what the log
msg says on STDOUT, we want to upload STDOUT to ourselves
when the script is about to exit.
Thus, we need FTP session information from the FTP
module hierarchy and we need log information from the util
package.
If Perl had a rigorously defined protocol for the sequence
in which objects were destroyed (I imagine Eiffel, Smalltalk
and other such languages probably do...), then I could
simply code my destructor with this knowledge.
| [reply] |
This is an attempt to gain some summary facts about objects
and destructors, some of which I dont believe was covered in
the OOP Tour de Force "Object-Oriented Perl" by Damian
Conway. So basically I have a set of things here which I am
inducing must be true based on what tye and merlin have
said, but am not sure and could not find the answer else
where and some of which I just thought up myself:
- It may be wise to use signal handlers to deal with
this situation? Or will all Perl data and functions be
destroyed by the time the signal to end the Perl program
is sent?
- If class A has a reference to class B, then even though
Perl DESTROYs are done in mem alloc order (as stated by
merlyn, we can gain some control over the order of
destruction by maintaining a reference to class B.
However, this reference must be lexically scoped? Why?!
| [reply] |
A Perl variable (such as a scalar, an array, but most-importantly an
object) is destroyed when its reference count goes to zero.
Reference counts usually go to zero when you leave the scope in which the
object was declared (unless references to it still exist elsewhere) or
right after the last object to have a reference to it is destroyed.
This is very handy since if $a needs $b, then $a holds a
reference to $b. This will mean that $a is destroyed before
$b so that $a's DESTROY method can use $b rather safely.
The "rather" is because there are some cases where this
destruction order guarantee will not be honored.
The biggest exception is global variables. The reference count on a global
variable (A.K.A. a package variable or an "our" variable) never goes
to zero. All globals are destroyed when the Perl interpretter is torn
down in a phase called, dramatically enough, "global destruction".
During this phase, all variables are destroyed without regard to
reference counts and in an order that is probably best thought of as
simply "undefined". The order is actually defined, but it has changed
and probably will change again and isn't a particularly useful order
from the script writer's perspective, so you'll have to go look it (well,
them) up if you are really curious (that may be what merlyn
was referring to when he talks about memory allocation order).
I was worried that an unexpected call to die would also
simply trigger global destruction, resulting in "random" destruction
order again (that would be bad). However, testing shows that
die does an orderly unwinding of the nested scopes,
decrementing reference counts and destroying things in the desired order.
Uncaught signals that kill your process will prevent the destruction of
any and all Perl variables. The operating system will simply free the
memory allocated to the process -- no Perl code will be given a chance to
"clean up". So you'll want to catch likely signals and try as safely as
possible to tell your program to shut itself down in an orderly manner.
With proper use of destructors, a simple
$SIG{HUP}= sub { die "Caught HUP\n" };
is all it takes. It isn't completely safe but only because Perl signal
handlers aren't completely safe no matter what they do.
So I would recommend not doing destruction in signal handlers
(die in the signal handler and let Perl do the destruction).
I would also recommend not using END since such code usually
needs to happen after you are sure you are done with some things but
before you have destroyed other things. If you do clean up in destructors,
then it usually just falls out that the clean up is done in the correct
order and is done whether the program exiting normally or failed (if
the operating system gives you that chance).
Oh, and circular references will prevent members of the circle and things
that they refer to from being destroyed until the global destruction phase.
Note that even if Perl detected and destroyed circular references, the
order of destruction would not be easy to predict since there is no "top"
in a circular reference.
-
tye
(but my friends call me "Tye")
| [reply] [d/l] [select] |