musiKk has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellow Monks,

recently I needed to keep some internal state between two method calls to a Moose object. I know now that the way to do that is to create an attribute with a name with a leading underscore. However I tried it like so:

has priv_attr => ( is => 'rw', isa => 'Str', reader => '_priv_attr', writer => '_priv_attr' );

I used this attribute in a method:

sub do_stuff { my $self = shift; $self->_priv_attr( 1 ); $self->_priv_attr; }

However, upon calling the method do_stuff the following error occurs:

Attribute (priv_attr) does not pass the type constraint because: Valid +ation failed for 'Str' with value undef at ./test.pl line 22 Foo::do_stuff('Foo=HASH(0x8d02c18)') called at ./test.pl line +28

So setting kinda works (in the sense that it doesn't fail) but the value is undefined afterwards. Is there some logic in that? To me it feels like a bug but I'm not very experienced in Moose.

Copy and paste ready code is here:

#!/usr/bin/env perl use warnings; use strict; { package Foo; use Moose; has priv_attr => ( is => 'rw', isa => 'Str', reader => '_priv_attr', writer => '_priv_attr' ); sub do_stuff { my $self = shift; $self->_priv_attr( 1 ); $self->_priv_attr; } 1; } Foo->new->do_stuff;

Replies are listed 'Best First'.
Re: Private Attributes in Moose
by ikegami (Patriarch) on Jul 22, 2011 at 21:14 UTC
    Since you are telling Moose to create two functions (a reader and a writer) with the same name, it's no wonder you are having problems!
    has priv_attr => ( accessor => '_priv_attr', isa => 'Str', );
    has _priv_attr => ( init_arg => 'priv_attr', is => 'rw', isa => 'Str', );
    has _priv_attr => ( is => 'rw', isa => 'Str', );
    has _priv_attr => ( init_arg => undef, is => 'rw', isa => 'Str', );
    1: Can be initialised using ->new( priv_attr => ... ) 2: Can be initialised using ->new( priv_attr => ... ) 3: Can be initialised using ->new( _priv_attr => ... ) 4: Cannot be initialised from outside the class.

      That's it. I wasn't aware of accessor. It would've been nice if Moose had used accessor internally after seeing that both reader and writer have the same name but I'm sure that's debatable. Thank you.

        It's actually Class::MOP (not Moose) that uses those, but yeah, I don't see the harm in adding that functionality.
Re: Private Attributes in Moose
by choroba (Cardinal) on Jul 22, 2011 at 21:17 UTC
    I get the same error if I use just the name "attr" for the accessors. So the "privateness" is not the problem here. If you want the same method to be the reader and writer, define it as accessor:
    accessor => '_priv_attr'