Flexing Moose

Stevan on 2006-08-11T18:24:12

I tried to build Moose to be a very flexible system. Pretty much all it's behaviors can be customized by overriding/extending it's default metaclasses. However, metaclass hacking can be both scary and very tricky, which is where Moose::Policy comes in.

One of the most common complaints I have heard about Moose is that it does not support { get, set }_foo (Perl Best Practicies approved) style accessors out of the box. Of course, this is easily done with a custom attribute metaclass, but that's not what people tend to want to hear. Now, with Moose::Policy it is as simple as this:


package Point;
use Moose::Policy 'Moose::Policy::FollowPBP';
use Moose;

has 'x' => (is => 'rw', isa => 'Int');
has 'y' => (is => 'rw', isa => 'Int');

Now Point has get_x, get_y, set_x and set_y methods generated for it's accessors.

Moose::Policy is basically a way to manage a set of metaclass customizations on a class-per-class basis without having to deal with those metaclasses directly. It also makes it pretty easy to package up these customizations for distribution with your project since a Policy is just another Perl 5 package file (see Moose::Policy for some examples).

The future plans for Moose::Policy include creating a number of roles which can be composed together to create custom policies without even having to touch metaclasses at all.

So, if you have looked at Moose and thought to yourself, "I would use it if only it had x feature", then let me know. Chances are that feature can be made into a Moose::Policy and we can add it to the distribution.

- Stevan


Moose

sigzero on 2006-08-11T20:53:44

That is very nice and very flexible.

lvalue accessors

kag on 2006-08-12T04:18:49

I decided to take the Moose out for a test drive, and ran into:

has 'count' => (is=>'rw', isa=>'Int');

$thing->count++; # fails!
$thing->count($thing->count + 1); # ugly!

Are lvalue accessors considered harmful, or would this make a good Moose::Policy?

Re:lvalue accessors

Dom2 on 2006-08-13T10:03:50

Yes, lvalue accessors are pretty useless in the real world. That's because you don't get a chance to intercept the value that's being assigned to. You can't (say) step in and clone something before it's assigned.

-Dom

Re:lvalue accessors

Aristotle on 2006-08-21T01:50:37

Unless, of course, you return a tied value…

Somehow, it feels like this discussion has already happened a couple times before…

Re:lvalue accessors

Dom2 on 2006-08-21T06:13:03

Very true, but it does start to feel like a lot of work that could be sidestepped by using a mnore traditional approach.

-Dom

Re:lvalue accessors

Stevan on 2006-08-17T18:52:56

Well to be honest, I am not sure what lead you to think that would work in the first place ;)

I will admit that $thing->count($thing->count + 1) is ugly, but lvalue accessors are really problematic in a lot of ways.

It has been suggested before that certain types could have additional accessors, so that this $thing->count($thing->count + 1) could become $thing->count_increment() or some such. But of course this is not always desired, so probably wouldnt be a good thing to force on all situations. But really, at this point though, I have not seen a good proposal for how this feature would look and work, so it remains just an idea. Until then, you could alway write your own increment_count method.

-- Stevan

Parameter names

bart on 2006-08-12T10:22:10

I must say I don't feel much for you choice of names for the parameters, most of all, for the "is". It's too vague. This reads just as natural as yours, doesn't it?
has 'x' => (is => 'Int');
And "isa" sounds more like a tradition, than as a good name.

What names would I propose? I don't think I have found really good names, but I have a few suggestions. For "is", I'd call it "access". After all, you're trying to control the access rights to the attribute. As for the other, I'm thinking of something like "type". Not really a good name, I admit, as that word could mean anything too. So my preliminary proposal is:
has 'x' => (type => 'Int', access => 'rw');
Maybe the name for the type could just be dropped, as it probably is required:
has 'x' => ('Int', access => 'rw');

Re:Parameter names

Stevan on 2006-08-17T18:46:10

Well, is => 'rw' and is => 'ro' are borrowed directly from Perl 6. And 'isa' has a very well known meaning in the Perl community, so I would rather stick to that then try to create my own. As for dropping the name for the type, this would force an ordering on the options list, which would make things trickier.

The changes you suggest could easily be done using Moose::Policy as well, see Moose::Policy::FollowPBP for an example. Basically you just preprocess the %options passed to has and turn them into something Moose recognizes. In fact, is => 'rw' is just a macro for accessor => 'foo' and is => 'ro' for reader => 'foo'.

- Stevan

"Its" and not "It's"

Shlomi Fish on 2006-08-13T09:26:46

You kept misspelling "Its" (I.e: whatever belongs to it) as "It's" (I.e: "it is"). Please pay attention to this next time.