in reply to Moose and BUILD

Maybe you should start with what you want to achieve in the end.

If y always depends on x, don't make it an attribute, but rather a method that calculates the value of y.

If you want to make it a default, use Moose's default facility:

use Moose; has 'y' => ( is => 'Num', is => 'rw' ); has 'x' => ( is => 'Num', is => 'rw', default => sub { sqrt(shift->x) }, );

I'm not a Moose specialist, but I guess that one reason the code does not do what you want is that you try to call methods on objects that haven't been constructed yet.

I also don't see why you want to call a derived BUILD method before the parent BUILD method. Just let the parent construct the parent part of the object, and then do whatever you want in the child.

Replies are listed 'Best First'.
Re^2: Moose and BUILD
by ikegami (Patriarch) on Jun 15, 2011 at 20:56 UTC

    The type is specified using isa, and you need lazy => 1 to make sure the default isn't calculated too soon.

    use Moose; has 'x' => ( is => 'rw' isa => 'Num', ); has 'y' => ( is => 'rw', isa => 'Num', lazy => 1, default => sub { sqrt($_[0])->x) }, );

      Good catch on the is, just a brain typo from rapidly throwing together running example code. It didn't matter in this case as I wasn't trying to use bad values in my test script.

      I will look into the lazy flag on the attribute and get a better idea of what it does.

        Always use lazy when the initialiser relies on another field of $self.

        It cause the initialiser to be called when the field is read instead of being called on construction.

Re^2: Moose and BUILD
by tj_thompson (Monk) on Jun 15, 2011 at 20:49 UTC
    It looks like maybe a better way to do this is to instead hook into BUILDARGS as this is executed before the object is created and allows for argument modification. I could explicitly set the value of x passed into the BUILD method and set an empty build method for Foo::Bar.
      Modifying Foo::Bar to this:
      package Foo::Bar; use Moose; extends 'Foo'; use Data::Dumper; around 'BUILDARGS' => sub { my ($orig, $class, %args) = @_; print STDERR "Foo::Bar::BUILDARGS running.\n"; $args{x} = 25; return $class->$orig(%args); }; 1;

      Seems to do what I want. Foo::BUILD is only executed once and it receives the updated 'x' value prior to BUILD execution, so 'y' is only calculated once. Here is the output in this case:

      plxc16479> ex.pl Foo::Bar::BUILDARGS running. Foo::BUILD running $VAR1 = bless( { 'y' => '5', 'x' => 25 }, 'Foo::Bar' );
Re^2: Moose and BUILD
by tj_thompson (Monk) on Jun 15, 2011 at 20:37 UTC

    My example above is very simple code in which transforming the input 'x' into the final attribute value 'y' is trivial. Assume instead it's not trivial to transform the input 'x' into the final value 'y'. In this case, you would be doing the transform work twice if you build the parent, then build the child and change the value the parent arrived at. It could be done, but it strikes me as poor code.

    My concept here, and perhaps I'm approaching it wrong, is that if the base class were to be instantiated, the input 'x' value would be provided. However, if the sub class were instead instantiated, I would like to lock a particular input value of 'x' in.