Last week found me explor­ing Object::Pad as an alter­na­tive to the Moo object-​oriented frame­work for Perl since the for­mer is pro­to­typ­ing the syn­tax and con­cepts for a pro­posed built-​in OO frame­work named Corinna. I had to put that par­tic­u­lar project on hold as dbcrit­ics cur­rent design is a bit too role-​happy and Object::Pad cur­rent­ly lacks method mod­i­fiers as in Moo. (Corinna is explic­it­ly skip­ping them for its cur­rent min­i­mum viable prod­uct.) Thankfully, devel­op­ment con­tin­ues at a rapid pace. For instance, author Paul Evans has already addressed a prob­lem I ran into when attempt­ing to exam­ine slot val­ues in the debugger.

But I want­ed to high­light a point I made in one of the com­ments last week: Object::Pad’s slots (a.k.a. fields, attrib­ut­es, what­ev­er) are pri­vate by default, com­plete­ly unex­posed to oth­er class instances unless they mon­key with the meta-​object pro­to­col. Unless you explic­it­ly define or gen­er­ate some kind of acces­sor method, these slots act like lex­i­cal (a.k.a. my) vari­ables and are only avail­able to meth­ods with­in the class.

Here’s an example:

use v5.14; # for say and package blocks
use Object::Pad 0.50;
use Feature::Compat::Try;

class Local::MyClass {
    has $arg           :param  = 'hello';
    has $readable_slot :reader = 'world';
    has $private_slot          = 'shh';

    method show_slots {
        say "You passed me $arg in the constructor.";
        say "I can see $readable_slot and you can use it as a reader.";
        say "Here's me using the reader too: ", $self->readable_slot;
        say "But only I can see $private_slot.";
        return;
    }
}

package main {
    my $obj = Local::MyClass->new(arg => 'foo');
    $obj->show_slots();
    say $obj->readable_slot;

    # Nope: Not a HASH reference
    try { say $obj->{private_slot} } catch ($e) { say "Nope: $e" }

    # Nope: Can't locate object method "private_slot" via package "Local::MyClass"
    try { say $obj->private_slot } catch ($e) { say "Nope: $e" }
}

This stands in stark con­trast to Perl’s more low-​tech hashref-​based objects, where all attrib­ut­es are avail­able sim­ply through deref­er­enc­ing the instance, e.g., $object->{foo}. Although dis­cour­aged, OO purists some­times ding Perl for this kind of unen­forced encap­su­la­tion, and I myself have seen code­bas­es that vio­late it despite the con­ven­tion of pre­ced­ing pri­vate method and attribute names with an under­score (_).

Unfortunately, there is not yet any way to declare an Object::Pad method pri­vate. You could use lex­i­cal sub­rou­tines, but then you lose the con­ve­nience of a pre-​made $self vari­able and acces­si­bil­i­ty through the MOP. The Corinna pro­pos­al lists sev­er­al dif­fer­ent types of meth­ods includ­ing pri­vate ones, so maybe this is an area for future Object::Pad development.

Another open ques­tion from the com­ments: How is [Object::Pad] on mem­o­ry and speed com­pared to Moo and blessed objects?” Luckily the pro­lif­ic per­lan­car has already added Object::Pad to his Bencher::Scenarios::Accessors dis­tri­b­u­tion, and from that, it appears that between it and Moo, Object::Pad is faster on start­up, neck-​and-​neck on object con­struc­tion and acces­sor gen­er­a­tion, and slow­er on reads and writes. (Note that Object::Pad is a fast-​moving tar­get so these fig­ures may not track with the lat­est ver­sion’s changes.) It’s no sur­prise that plain blessed objects fared bet­ter than both in most sce­nar­ios except for reads, where Moo was faster than hash-​based objects but slow­er than array-based.

I expect that should Corinna be built into Perl it would nar­row that gap with blessed objects, but in my mind, the advan­tages of using an object sys­tem out­weigh the per­for­mance hit 95% of the time. As far as bench­mark­ing mem­o­ry goes, I still need to test that on a Linux box (maybe my new VPS?) once I get more famil­iar with the Bencher framework.