Skip to content

Destructors

Ovid edited this page Sep 14, 2021 · 10 revisions

Please see the main page of the repo for the actual RFC. As it states there:

Anything in the Wiki should be considered "rough drafts."

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 Corinna ain't Moose. Moose has BUILD and DEMOLISH for construction/destruction, so Corinna 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 one method, is_global:

class Cor::Destruction {
    has $is_global :reader :new :isa(Bool);
}

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.

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.