-
Notifications
You must be signed in to change notification settings - Fork 19
Destructors
Click here to provide feedback.
To better understand this document, you should read Class Phases.
Just as we have constructors, we also need destructors. These are special methods called during object destruction to ensure that everything that needs to be cleaned up/finalized, is cleaned up/finalized.
Core Perl has an issue here:
#!/usr/bin/env perl
use Less::Boilerplate; # personal version of Modern::Perl
package Parent {
sub new { bless {} => shift }
sub inherited { say "Inherited" }
sub DESTROY { say "Parent" }
}
package Child {
our @ISA = 'Parent';
sub new { bless {} => shift }
sub DESTROY { say "Child" }
}
{
my $thing = Child->new;
$thing->inherited;
}
say "Done";
Running that prints:
Inherited
Child
Done
Note that Parent
is not printed because the parent destructor is not called.
Thus, you need to call $self->next::method
at the end of every DESTROY
.
Moose has sane object destruction via
DEMOLISH,
but Cor ain't Moose. Moose has BUILD
and DEMOLISH
for
construction/destruction, so Cor has CONSTRUCT
and DESTRUCT
for
its object construction/destruction.
Most of the time you won't need to add behavior to the DESTRUCT
phase, but
if you do:
DESTRUCT ($destruction) {
if ($destruction->is_global) {
...
}
else {
...
}
}
The DESTRUCT
phase receives a Cor::Destruction
object which currently has
two methods, is_global
and refcount
:
class Cor::Destruction {
has $is_global :reader :new :isa(Bool);
has $refcount :reader :new :isa(PositiveOrZeroInt);
}
The Cor::Destruction
object is not created unless there is a target
DESTRUCT
phaser to pass it to. Thus, Cor::Destruction
will never be passed
to itself, avoiding an infinite loop.
The refcount
attribute is potentially useful if the refcount drops to zero
and you want to do a cleanup. This is potentially safer than in global
destruction because in the latter, the interpreter is going away and there are
few guarantees as to what you can and cannot do.
In core Perl, it's often hard to know exactly when data gets destroyed in object destruction. For Cor, we suggest a deterministic order:
- Children destroyed before parents
- Instance data before class data
- Slots destroyed in reverse order of declaration
With the above, we can reason about exactly when and how object destruction occurs.
Further, the order of destruction has been choses to ensure that dependencies get destroyed after the things that depend on them. Thus, declare you database handle at the top of your attribute list and you'll always be guaranteed the handle is there.
Corinna—Bringing Modern OO to Perl