Introducing Sub::Trigger::Lock

Sub::Trigger::Lock is a workaround for the problem that Moose read-only attributes aren't really read-only; at least, not in the way that people might expect them to be. Here's an example:

   package Foo {
      use Moose;
      
      has bar => (is => 'ro', isa => 'ArrayRef');
   }
   
   my $foo = Foo->new( bar => [1,2,3] );
   push @{ $foo->bar }, 4;   # does not die!

A read-only attribute containing an arrayref of hashref cannot have the attribute changed to reference another array or hash. However, the contents of that array or hash are not magically read-only.

Sub::Trigger::Lock can make them magically read-only.

   package Foo {
      use Moose;
      use Sub::Trigger::Lock;
      
      has bar => (is => 'ro', isa => 'ArrayRef', trigger => Lock);
   }
   
   my $foo = Foo->new( bar => [1,2,3] );
   push @{ $foo->bar }, 4;   # kablammo!

Sub::Trigger::Lock also contains various utility functions for temporarily unlocking and re-locking the array, which allows the Foo method to provide its own API for altering the array:

   package Foo {
      use Moose;
      use Sub::Trigger::Lock -all;
      
      has bar => (is => 'ro', isa => 'ArrayRef', trigger => Lock);
      
      sub bar_append {
         my $self  = shift;
         my $guard = unlock $self->bar;
         push @{ $self->bar }, @_;
      }
   }
   
   my $foo = Foo->new( bar => [1,2,3] );
   $foo->bar_append(4);      # ok
   push @{ $foo->bar }, 5;   # kablammo!

That's about it. Sub::Trigger::Lock allows you to stop people from altering your object's hashrefs and arrayrefs from underneath it. It forces them (or at least strongly encourages them) to use your API to alter your object's attributes.

3 Comments

Too good, Toby. Keep up the good work. However it would have been nicer if it comes under the namespace of Moose::* or MooseX::* in my humble opinion.

You're not locking the external access, but the internal implementation. IMO that's the wrong solution.

Leave a comment

About Toby Inkster

user-pic I'm tobyink on CPAN, IRC and PerlMonks.