Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Moose - nalia

by doc_faustroll (Scribe)
on Mar 21, 2008 at 17:27 UTC ( [id://675482]=perlquestion: print w/replies, xml ) Need Help??

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

I'm enjoying the benefits of using Moose, and I wanted to enquire into some of the finer aspects of development with Moose.

Most of it is intuitive and very helpful. My compliments to the developers.

I have a couple of questions nonetheless:

I note that there exists both a trigger and a builder option. The trigger option, by use and testing has become clear. The builder option is somewhat similar, although it is passed as a scalar method name and not a coderef. Why a builder and a trigger option, and what are the finer points of the builder option? I ask as much to divine the intent of and the future direction of the design and development of Moose as for practical reasons.

as in:

has 'x' => (is => 'rw', isa => 'HashRef', builder => 'build_x'); has 'y' => (is => 'rw', isa => 'HashRef', trigger => \&y_trigger);

The trigger is as the docs say, "a CODE reference which will be called after the value of the attribute is set. The CODE ref will be passed the instance itself, the updated value and the attribute meta-object."

There is not too much information on builder in the Moose perldoc. Anyone care to elaborate?

Now for a more fun question. Metaclasses have been described as a solution in search of a problem. Anyone care to share any clever problems and solutions using Metaclasses in Moose?

Replies are listed 'Best First'.
Re: Moose - nalia
by stvn (Monsignor) on Mar 21, 2008 at 19:19 UTC

    First, thanks for the compliments, and sorry about the docs. We are well aware of the deficiencies in the docs and actually Moose is currently under a feature freeze until the docs are brought up to date. We had a mad rush of features and improvements in the last few months, but (as will always happen) the docs kind of lagged behind. The next few releases will probably be entirely doc updates (and bug fixes of course). In the meantime, there are a number of articles and presentations linked to on the Moose site that might help fill in some holes (also note the recently uploaded podcast from the recent PDX.pm meeting).

    The builder option is somewhat similar, although it is passed as a scalar method name and not a coderef. Why a builder and a trigger option, and what are the finer points of the builder option?

    The 'builder' option is actually is actually documented in Class::MOP::Attribute, one of the things we are going to do is to move some of those docs up to Moose for easier access.

    The 'builder' option is actually closer to the 'default' option then it is 'trigger'. A 'builder' is used to initialize an instance's slot. The reason it is only a string is that it is meant to be a method name and therefore to be easily overrideable in a subclass. Here is an example:

    package Foo; use Moose; has 'bar' => (is => 'rw', builder => 'build_bar'); sub build_bar { 'Foo::bar' } package Foo::Bar; use Moose; extends 'Foo'; sub build_bar { 'Foo::Bar::bar' } print Foo->new->bar # "Foo::bar" print Foo::Bar->new->bar; # "Foo::Bar::bar"
    In some ways builder can be seen as being equivalent to:
    has 'foo' => (is => 'rw', default => sub { $_[0]->build_foo });
    although the actual implementation is different (mostly for performance reasons).

    Now for a more fun question. Metaclasses have been described as a solution in search of a problem. Anyone care to share any clever problems and solutions using Metaclasses in Moose?

    Actually, Moose itself would not be possible without the metaclasses provided by Class::MOP. That is justification enough for metaclasses for me :)

    Also, Moose can be extended using metaclasses, some examples of that include:

    I will say that it is rare that you need to use the metaclasses in Moose and they should always be used sparingly. It is a powerful tool and one that is really easy to abuse, not unlike Perl itself actually.

    -stvn
      Thanks stvn,

      It looks also as if trigger provides the instance to the coderef whilst builder does not?

      Moose is not so much lacking in docs as well designed enough to be immediately useful! Excellent work.

      Perhaps rather than use trigger, I should be overriding the constructor? I'm using trigger for creating the initial state of the object.

        If you just want to set the initial state, you should either use builder, or the aptly-name 'default'.

        has 'foo' => ( builder => 'build_foo', ); sub build_foo { my $self = shift; return 'blah'; } # OR has 'foo' => ( default => sub { my $self = shift; return 'blah'; }, );

        We're not surrounded, we're in a target-rich environment!
        It looks also as if trigger provides the instance to the coderef whilst builder does not?

        Actually (as jasonk points out) both 'builder' and 'default' get the instance as their first arg. Of course, if the attributes are not marked as 'lazy', then that instance may not be built/initialized completely. My basic rule is that if you want to use the value of another attribute in your 'default' or 'builder' then make that attribute 'lazy'. The performance costs are minimal (I never actually benchmarked it, but knowing what it does under the covers it can't be too bad), and it will save you any headache later on (since it basically constructs using hash ordering, it might work fine today, and break tomorrow given the random-ness of hash ordering). More information about lazy can be found in Moose::Cookbook::Recipe3.

        Moose is not so much lacking in docs as well designed enough to be immediately useful! Excellent work.

        Thanks, I blame @Larry (aka - Perl 6 designers) and the various designers of CLOS, Smalltalk, Ruby and OCaml, as I stole all the good ideas from them. But we still need to clean up the docs more. As was discussed on #moose last night, the Moose::Cookbook tend to be the best way to learn Moose, it seems to be most digestable through example rather then straight POD docs on all the meta-objects and such.

        Perhaps rather than use trigger, I should be overriding the constructor? I'm using trigger for creating the initial state of the object

        Again, as jasonk said, it is better to use 'default' and 'builder' for initializing state, it is what they are intended for. The 'trigger' option is actually run every time the value is set.

        As for overriding &new, that is generally not a good idea with Moose as it disqualifies your class from getting an inlined constructor when you make it immutable. It is better to use things like 'default', 'builder' or 'trigger', or if those are not enough you can use the &BUILD method (this is documented in the description for &BUILDALL in the docs for Moose::Object), and if that still is not enough people will use 'around' to override &new (which is something we plan on making optimizable, although it currently is not, future-proofing++).

        -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://675482]
Approved by kyle
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-03-29 09:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found