graphql-perl - MooX::Thunking - Deferred computation attributes

As part of porting GraphQL to Perl (sponsored by Perl Careers), one of my goals is to use the best possible practice in making rigorous code. One way to use this is to imitate the style of the JavaScript reference implementation's use of immutable data structures.

One problem arising is creating objects that have a reference to themselves. If the objects created were mutable, then one would simply create the object, then set the relevant attribute to include the object reference. If the objects are immutable this is not possible. For example:

package GraphQLType;
use Moo;
use Types::Standard -all;
has [qw(children)] => (
  is => 'ro',
  isa => ArrayRef[InstanceOf['GraphQLType']],
  required => 1,
);

package main;
my $type;
$type = GraphQLType->new(children => [$type]);

There is a chicken-and-egg problem here because when the new method runs, $type is undefined, so it is not an object of the right class. A way round this is to use "thunks", so that where this sort of circular situation arose, I could instantiate the object like this (but still be able to supply a final, non-coderef value as well):

my $type1;
$type1 = GraphQLType->new(children => sub { [$type1] });
my $type2 = GraphQLType->new(children => [$type1]);

My solution to this is MooX::Thunking. It provides an additional possibility for the is option to has:

package GraphQLType;
use Moo;
use MooX::Thunking;
use Types::Standard -all;
has [qw(children)] => (
  is => 'thunked',
  isa => ArrayRef[InstanceOf['GraphQLType']],
  required => 1,
);

package main;
my $type;
$type = GraphQLType->new(children => sub { [$type] });

As of today's version 0.07, the isa type does not need to accept a code-ref (or suitably overloaded object).

For more discussion of this, see this StackOverflow question.

Leave a comment

About Mohawk

user-pic I blog about Perl.