tags:

views:

99

answers:

2

I'm an absolute newbie to Moose and so far I have read Moose and most of the Cookbook.

There a few things I don't get. I created the following package:

package MyRange;

use Moose;
use namespace::autoclean;

has [ 'start', 'end' ] => (
    is       => 'ro',
    isa      => 'Int',
    required => 1,
);

__PACKAGE__->meta->make_immutable;

1;

Then:

use MyRange;    
my $br = MyRange->new(
    start                => 100,
    end                  => 180
);

Now I can access my fields using e.g. $br->{start}, but I can also modify them (although they are "read only") using e.g. $br->{start}=5000. I can also add new keys like $br->{xxx}=111.

Am I missing anything? Isn't the object protected in some way? What's the meaning of ro?

+12  A: 

When you said is => 'ro' you told Moose to create read-only accessors for you, that is, a reader method. You call that as

$br->start;

or

$br->end;

Setting the attributes using those methods will result in an exception:

$br->start(42);

If you had used is => 'rw', then the above would work and update the attribute's value.

What you're doing is direct hash access on the object, which violates encapsulation and shouldn't ever be necessary when using Moose.

The Moose manual, i.e. all the documents under the Moose::Manual namespace explain that in detail. A good starting point for questions like this is probably Moose::Manual::Attributes.

rafl
+1 Thank you! A follow-up, if I may: I have some fields which are no required. If they are not set, and I try to access those `undef` values I would like to get an error. Should I set a reader for each of them? Or perhaps to use some `die`-like sub in `default`?
David B
You might want to create a new question for a more detailed answer on this, but: Do you have a design where values are initially not required, but the user is allowed to fill them out later using writer methods and must do so before calling some functionality that uses it? Most of the time, you should probably re-think your design there, but in the rare cases where it makes sense, my `MooseX::LazyRequire` extension might be helpful. All that does is making an attribute required, but defering the exception from construction time to the time the attr is accessed.
rafl
Also note that you can ask Moose to generate `predicate` methods for you. Those you can use to explicitly check if a value has been set for some attribute through either the constructor or writer methods. This is especially handy for attributes that aren't required and for which `undef` is a valid value.
rafl
+2  A: 

When you access to the attribute with $br->{start}, you are bypassing the accessor and you are adressing directly the underlying Moose implementation. You can do it, but you are not supposed to. Also, if Moose changes the implementation, your code will break.

You should instead access the attribute using the accessor method:

my $start = $br->start;

When you say that the attribute is 'RO', it means you are not allowed to change the attribute value using the accessor:

$br->start(32);
dolmen