Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Moose: apply Role at Runtime (build vs. default) [solved]

by Brutha (Friar)
on Apr 02, 2013 at 12:42 UTC ( [id://1026677]=perlquestion: print w/replies, xml ) Need Help??

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

Hello fellow monks,

after working through Moose Best Practices and various discussions, I decided to use build instead of default for my attributes. So far so good.

Now I have a role with lazy attributes that I apply at runtime with Moose::Util qw(apply_all_roles). This also works fine. With one exception. I get the message "You cannot have a lazy attribute (myattr) without specifying a default value for it". Calling the _build function from default works.

From Perl common sense I would say, the object is already built before the Role is applied. So you have to use default values for initialization. And so I do something like:

has 'myattr' => ( is => 'ro', isa => 'Int', lazy => 1, default => \&_build_myattr, # build => '_build_myattr', );

Did I miss something?

What are best practises in my case?

Thank you for your thoughts

Update: see comment below, it's a typo. It is a "builder" instead of "build"

And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
(Terry Pratchett, Small Gods)

Replies are listed 'Best First'.
Re: Moose: apply Role at Runtime (build vs. default)
by tobyink (Canon) on Apr 02, 2013 at 16:13 UTC

    Works for me!

    use v5.14; use strict; use warnings; package MyObject { use Moose; } package MyRole { use Moose::Role; has myattr => ( is => 'ro', lazy => 1, builder => '_build_myattr', ); sub _build_myattr { "value"; } } my $obj = "MyObject"->new; Moose::Util::apply_all_roles($obj, "MyRole"); say $obj->myattr;

    Also, whenever you call a builder method from a coderef, make sure you call it as a method so that subclassing works.

    # Not this... default => \&_build_myattr, # This! default => sub { shift->_build_myattr(@_) },
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

      First, thank you for your answer. Guess what, it works for me as well :(

      The reason for my late answer is, that my problem is a bit more complex. I have a base class and create on the fly a Role and then a Class from that Role and the baseclass. Later I apply that role with the default/builder problem. Putting that together in my sample code works as well with builders.

      Now I try to figure out where the difference is between my real code and the sample, as the real code still does give that error. (Not) Using MooseX::Declare does not make a difference.

      And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
      (Terry Pratchett, Small Gods)

Re: Moose: apply Role at Runtime (build vs. default)
by Brutha (Friar) on Apr 08, 2013 at 12:49 UTC

    Hurray, finally I solved it.
    Stupid, as always in such cases.

    Take a look at my attribute's code:

    has 'myattr' => ( is => 'ro', isa => 'Int', lazy => 1, default => \&_build_myattr, # build => '_build_myattr', );

    Simply exchanging the comment between "default" and "build" does not work and gives the mentioned error.
    I also had to make a builder out of build. I had to debug deep into Moose until I found this typo

    Thank You for Your patience.

    And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
    (Terry Pratchett, Small Gods)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (11)
As of 2024-04-23 21:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found