Blessing functions in Perl

Finding clever uses for vanilla (non-Moose) Perl object constructor.


Note: this is really just a fun fact that should not be used in real systems. It is much easier to think about architecture when it does not consist of some custom funny elements.

Consider the package:

package Example;

sub instance
{
        my ($package, $meta) = @_;
        die "Reference was expected"
                unless ref $meta;
        # bless metadata as package's object
        return bless $meta, $package;
}

As basic as it is, it allows blessing of any reference passed to the constructor. We're used to thinking about objects as dictionaries which hold method and field references inside. This can be twisted a little bit in Perl:

use Example;

# Source
open my $filehandle, "<", "datafile"
        or die "Couldn't open file";

# Reader
my $every_row = sub {
        return scalar <$filehandle>;
};

# Doer
my $inst = Example->instance($every_row);

We now have a version of our Example package which is not aware of the source of the data it's getting but capable of reading it at the runtime. This is dependency injection through higher order functions.

# In package 'Example'
use JSON;

sub next_row
{
        my ($source) = @_;
        my $row = $source->();

        # decode until eof
        return decode_json $row
                if defined $row;
}

# In script
while (my $row_json = $inst->next_row) {
        ... # handle json
}

It's also extremely easy to change the data source for the package to work on as it's the only piece of data associated with it. To be precise, you don't even need to instantiate if you don't intend to reuse or inject further. This requires exporting functions from the Example module using Exporter.

use Example qw(next_row);
# Assumes Example has next_row in EXPORT_OK

while (my $row_json = next_row $every_row) {
        ... # same thing
}

We can now swap our file datasource to database or API call with ease using only the bare-bones system that ships with Perl.


Comments? Suggestions? Send to feedback@bbrtj.eu
Published on 2019-07-26