Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Moose n00b question about writer / reader

3 views
Skip to first unread message

Andrew Hicox

unread,
Apr 19, 2015, 3:15:02 PM4/19/15
to mo...@perl.org
Hello Moose list,

Apologies if this is a dumb question, but I have repeatedly tried to understand this section of the documentation, and I need some help:


I want to create a class that has some attributes. However, there’s some logic that needs to be executed when setting values on these attributes. In some cases, I’ll need to throw an error like “you can’t set that value on this object attribute”, I also need to be able to modify the value on the way into the object sort of like a DECODE() statement in SQL, etc.

This seems like I’d just need to declare a writer sub for the attribute, do my logic in there, then set the attribute value or throw an error, right?

Why doesn't this work?

package Bogus {
use Moose;
has ‘value’, is => “rw”, writer => “_value”, isa => “Num”;
sub _value {
my ($self, $value) = @_;
## insert some logic here
$self->value($value);
return(1);
}
}

use Bogus;
my $a = new Bogus(value => 1);

Can what I’m trying to do even be done in Moose?
again, sorry for the dumb question. I’m quite sure I’ve just missed something in my understanding.

thanks everyone,

-Andy



(Harald Jörg)

unread,
Apr 19, 2015, 7:00:02 PM4/19/15
to mo...@perl.org
Hello Andrew,

you write:

> Apologies if this is a dumb question, but I have repeatedly tried to
> understand this section of the documentation, and I need some help:
>
> http://search.cpan.org/~ether/Moose-2.1404/lib/Moose/Manual/Attributes.
> pod#Accessor_methods
>
> I want to create a class that has some attributes. However, there’s
> some logic that needs to be executed when setting values on these
> attributes. In some cases, I’ll need to throw an error like “you can’t
> set that value on this object attribute”, I also need to be able to
> modify the value on the way into the object sort of like a DECODE()
> statement in SQL, etc.

You'll want to scroll half a dozen screenfuls downward on the same page
and check out the section titled "Triggers". These can be used to do
exactly the things you want.

Setting writer / reader, on the other hand, is just providing names to
the accessor routines which Moose creates automatically for you.

> This seems like I’d just need to declare a writer sub for the
> attribute, do my logic in there, then set the attribute value or throw
> an error, right?
>
> Why doesn't this work?
>
> package Bogus {
> use Moose;
> has ‘value’, is => “rw”, writer => “_value”, isa => “Num”;

make that trigger => "_value"

> sub _value {
> my ($self, $value) = @_;

...you'll get ($self,$value,$previous_value) = @_;

> ## insert some logic here

Your logic can check and modify $current_value, and if changed, pass it
to the writer (again), or even reinstate the previous value.

> $self->value($value);
> return(1);
> }
> }
>
>
> use Bogus;
> my $a = new Bogus(value => 1);
>
> Can what I’m trying to do even be done in Moose?
> again, sorry for the dumb question. I’m quite sure I’ve just missed
> something in my understanding.

I'm also a Moose beginner (more or less) and know this feeling very
well. There's a lot of stuff to read, and I was lucky to have a gentle
introduction at our Perl monger's meeting.

I have never tried the more sophisticated methods to achieve your goal:
declare how to check your value as described in
`perldoc Moose::Manual::Types`: type constraints can valuate the input
against the properties of a custom class, and coercion can modify the
value on the fly.
--
Cheers,
haj

Buddy Burden

unread,
Apr 19, 2015, 8:45:02 PM4/19/15
to mo...@perl.org
Andrew,

>> I want to create a class that has some attributes. However, there’s
>> some logic that needs to be executed when setting values on these
>> attributes. In some cases, I’ll need to throw an error like “you can’t
>> set that value on this object attribute”, I also need to be able to
>> modify the value on the way into the object sort of like a DECODE()
>> statement in SQL, etc.

> You'll want to scroll half a dozen screenfuls downward on the same page
> and check out the section titled "Triggers". These can be used to do
> exactly the things you want.
>
> Setting writer / reader, on the other hand, is just providing names to
> the accessor routines which Moose creates automatically for you.

Harald is absolutely correct. I don't know if this will help or not,
but here's how I think of it.

In Moose, just as in C++,[1] there's a distinction between
initialization and assignment. When you call a constructor, you're
initializing the attributes. When you call a mutator,[2] you're
assigning to an attribute. A trigger is a way to hook into to both
methods of setting the attribute.[3]

And, if that _doesn't_ help, feel free to ignore me. :-)


-- Buddy


[1] And maybe in other OO languages as well (Java, perhaps?).
[2] What we generally call an accessor. But, if your attribute is rw,
then it's technically a mutator.
[3] C++ doesn't have such a thing. Yet another reason I prefer Moose. :-)

Kent Fredric

unread,
Apr 19, 2015, 11:00:02 PM4/19/15
to Andrew Hicox, mo...@perl.org

On 20 April 2015 at 07:00, Andrew Hicox <and...@hicox.com> wrote:
This seems like I’d just need to declare a writer sub for the attribute, do my logic in there, then set the attribute value or throw an error, right?

Why doesn't this work?

package Bogus {
use Moose;
has ‘value’, is => “rw”, writer => “_value”, isa => “Num”;
sub _value {
my ($self, $value) = @_;
## insert some logic here
$self->value($value);
return(1);
}
}

use Bogus;
my $a = new Bogus(value => 1);

The initial mistake I believe you made was thinking that the argument to writer was intended to be a "I'll create this sub, Moose can use it".

Whereas that argument in this case is "Moose, create me a writer called _value".

So the RHS of that token is intended for more external interfaces, eg:

---

has value => ( is => 'rw', writer => "set_value" , reader => "get_value");
...
$object->set_value(  $arg );
$object->get_value(); # returns $arg

---


so:

$writer_sub -> internal attribute store
$reader_sub <- internal attribute store

$writer_sub and $readersub can sometimes be the same sub, which is the default case with "is => rw".

For comparion, see:  "is => raw", where $object->value won't exist.

Andrew Hicox

unread,
Apr 20, 2015, 9:30:02 AM4/20/15
to mo...@perl.org

Thanks guys! The thing I didn't understand was that reader and writer just change the name of the moose default accessor methods.

Looks like trigger will do what I want, though I have to ask ... is there a way to simply override the default moose accessor methods with your own?

-Andy

Chris Prather

unread,
Apr 20, 2015, 10:15:02 AM4/20/15
to Andrew Hicox, mo...@perl.org
The default accessors are pretty simple. Generally what people do is create a private one that they then call from their own method.

has foo => ( writer => '_foo' ... );
sub foo { ... $self->_foo($value) ... }

-Chris
0 new messages