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

I'm starting to learn Moose, and object-oriented programming in Perl in general. My apologies if I get the terms wrong or I'm missing something obvious.

Is there a way to create an attribute in Moose that is read-only to the outside world, but that the code in the package can change?

My application: the class stores various attributes (a representation of a Perforce changelist, as it happens). There is an immutable integer key (changelist number). It is storing these instances in an array indexed by the key. I would like the class to allow the caller to get the minimum and maximum key values seen so far. (It is not destroying any instances while the program is running, so these can be adjusted via sub BUILD.) But a caller should not be able to set them.

Since I'm learning Moose and Perl OO, I'd like to do it in "the standard Moose way", if any. (For example, the program outside the class could keep track of the min and max, but I'd like the class to track them instead.) Also, being naive, I'm thinking that Moose probably handles lots of grungy details correctly, and I wouldn't.

My thought was MooseX::ClassAttribute. But with class_has 'min_change' => (is => 'ro', ...), not even the package itself can change it.

I looked at writer=>, but isn't that visible outside too?

Is it kosher to just declare "my" variables (rw internally) and provide non-instance-based subs so that callers can read them (ro outside) -- does that work with inheritance and all that in the Moose framework? Any other notions? I'm afraid I'm at sea here.

Tim McDaniel, tmcd@panix.com

Replies are listed 'Best First'.
Re: Moose attribute: ro to public, rw in the class?
by bruno (Friar) on Apr 09, 2009 at 22:38 UTC
    You can do it easily by setting the attribute as readonly but providing a private writer:

    #!/usr/bin/perl use Modern::Perl; { package Foo; use Moose; has bar => ( is => 'ro', writer => '_set_bar', ); } my $foo = Foo->new; $foo->bar('something'); # outputs: # Cannot assign a value to a read-only accessor at # /home/brunov/tmp/pm.pl line 16 $foo->_set_bar('something'); say $foo->bar; # outputs: # something

    Nothing stops your class' consumers from setting bar using _set_bar; they should follow the convention that methods with preceding underscores are private.