Skip to content

Destructors

Ovid edited this page Jun 17, 2020 · 10 revisions

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.

Order of Data Destruction

In core Perl, it's often hard to know exactly when data gets destroyed in object destruction. For Cor, we suggest a deterministic order:

  1. Children destroyed before parents
  2. Instance data before class data
  3. 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.

Clone this wiki locally