Search code examples
perlmooseimmutability

How do I create a cyclic graph of immutable objects in Perl and Moose?


This could seem like an obviously hopeless case, but is there a trick to create a cyclic graph of immutable objects in Perl? Something like this:

package Node;
use Moose;
has [qw/parent child/] => (is => 'ro', isa => 'Node');

package main;
my $a = Node->new;
my $b = Node->new(parent => $a);

Now if I wanted $a->child to point to $b, what can I do?


Solution

  • I had to go and look at how really immutable languages do something like this, and I think the following is probably a reasonable attempt.

    use 5.10.0;
    {
    
        package Node;
        use Moose;
        has [qw(parent child)] => ( isa => 'Node', is => 'ro' );
    
        sub BUILD {
            my ( $self, $p ) = @_;
            return unless exists $p->{_child};
            my $child = Node->new( parent => $self, %{ delete $p->{_child} }, );
            $self->meta->get_attribute('child')->set_value( $self, $child );
        }
    }
    
    say Node->new( _child => {} )->dump
    

    Basically instead of trying to build the objects separately, you have the parent auto-vivify the child based on passing in it's arguments. The output for this is, which is I believe the structure you were wanting.

    $VAR1 = bless( {
                     'child' => bless( {
                                         'parent' => $VAR1
                                       }, 'Node' )
                   }, 'Node' );