2

In Perl/Tk, one can define textvariables for widgets. It's a reference to some scalar that holds the value. Someone showed me how to use Moose attribute coercion to use Moose attributes as textvariable (cool!). This is how it works:

subtype 'TkRef' => as 'ScalarRef';
coerce 'TkRef', from 'Str', via { my $r = $_; return \$r };
has 'some_val' => (is => 'rw', isa => 'TkRef', coerce => 1, default => 'default value');

$mw->Entry(-textvariable => $self->some_val);
$mw->Label(-textvariable => $self->some_val); # will always Show what we type into the entry

However, when I want to set a new value for the attribute, I have to dereference it like this:

${$self->some_val} = 'blarg'; # dereference

Simply setting the attribute won't work, as the reference needs to remain the same over the life of the object (that is, the attribute value itself cannot change).

Is there a way to use the nice Moose attribute coerce feature without losing the possibility to set the attribute with $self->some_val('blarg'); ? Some sort of reverse-coercion?

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
capfan
  • 817
  • 10
  • 26

1 Answers1

1

Make the accessors private, and then provide a wrapper for the accessor. Something like this:

subtype 'TkRef', as 'ScalarRef';
coerce 'TkRef', from 'Str', via { my $r = $_; return \$r };

has _some_val => (
   is       => 'rw',
   isa      => 'TkRef',
   coerce   => 1,
   init_arg => 'some_val',
   default  => 'default value',
);

sub some_val {
   my $self = shift;
   if (@_ and not ref $_[0]) {
      ${$self->_some_val} = shift;
   }
   elsif (@_ and ref $_[0]) {
      ${$self->_some_val} = ${+shift};
   }
   $self->_some_val(@_);
}
tobyink
  • 13,478
  • 1
  • 23
  • 35
  • This is so cool. Although the type coercion reminds me of the type-munging stuff of other programming languages - which is I don't and which is why I chose Perl after all - it does exactly what I want it to do. All that's left now is to encapsulate it so I don't have to see / write it every time I have such a variable. – capfan May 03 '14 at 11:37