6 Moose::Cookbook::Basics::Recipe3 - A lazy B<BinaryTree> example
13 has 'node' => ( is => 'rw', isa => 'Any' );
18 predicate => 'has_parent',
25 predicate => 'has_left',
27 default => sub { BinaryTree->new( parent => $_[0] ) },
33 predicate => 'has_right',
35 default => sub { BinaryTree->new( parent => $_[0] ) },
38 before 'right', 'left' => sub {
39 my ( $self, $tree ) = @_;
41 confess "You cannot insert a tree which already has a parent"
49 This recipe shows how various advanced attribute features can be used
50 to create complex and powerful behaviors.
52 The example class is a classic binary tree. Each node in the tree is
53 itself an instance of C<BinaryTree>. It has a C<node>, which holds
54 some arbitrary value. It has C<right> and C<left> attributes, which
55 refer to its child trees, and a C<parent>.
57 Let's take a look at the C<node> attribute:
59 has 'node' => ( is => 'rw', isa => 'Any' );
61 Moose generates a read-write accessor for this attribute. The type
62 constraint is C<Any>, which means literally means it can contain
65 We could have left out the C<isa> option, but in this case, we are
66 including it for the benefit of other programmers, not the computer.
68 Next, let's move on to the C<parent> attribute:
73 predicate => 'has_parent',
77 Again, we have a read-write accessor. This time, the C<isa> option
78 says that this attribute must always be an instance of
79 C<BinaryTree>. In the second recipe, we saw that every time we create
80 a Moose-based class, we also get a corresponding class type
83 The C<predicate> option is new. It creates a method which can be used
84 to check whether or not a given attribute has been initialized. In
85 this case, the method is named C<has_parent>.
87 This brings us to our last attribute option, C<weak_ref>. Since
88 C<parent> is a circular reference (the tree in C<parent> should
89 already have a reference to this one, in its C<left> or C<right>
90 attribute), we want to make sure that we weaken the reference to avoid
91 memory leaks. If C<weak_ref> is true, it alters the accessor function
92 so that the reference is weakened when it is set.
94 Finally, we have the the C<left> and C<right> attributes. They are
95 essentially identical except for their names, so we'll just look at
101 predicate => 'has_left',
103 default => sub { BinaryTree->new( parent => $_[0] ) },
106 There are two new options here, C<lazy> and C<default>. These two
107 options are linked, and in fact you cannot have a C<lazy> attribute
108 unless it has a C<default> (or a C<builder>, but we'll cover that
109 later). If you try to make an attribute lazy without a default, class
110 creation will fail with an exception. (2)
112 In the second recipe the B<BankAccount>'s C<balance> attribute had a
113 default value of C<0>. Given a non-reference, Perl copies the
114 I<value>. However, given a reference, it does not do a deep clone,
115 instead simply copying the reference. If you just specified a simply
116 reference for a default, Perl would create it once and it would be
117 shared by all objects with that attribute.
119 As a workaround, we use an anonymous subroutine to generate a new
120 reference every time the default is called.
122 has 'foo' => ( is => 'rw', default => sub { [] } );
124 In fact, using a non-subroutine reference as a default is illegal in Moose.
126 has 'foo' => ( is => 'rw', default => [] );
128 This will blow up, so don't do it.
130 You'll notice that we use C<$_[0]> in our default sub. When the
131 default subroutine is executed, it is called as a method on the
134 In our case, we're making a new C<BinaryTree> object in our default,
135 with the current tree as the parent.
137 Normally, when an object is instantiated, any defaults are evaluated
138 immediately. With our C<BinaryTree> class, this would be a big
139 problem! We'd create the first object, which would immediately try to
140 populate its C<left> and C<right> attributes, which would create a new
141 C<BinaryTree>, which would populate I<its> C<left> and C<right>
144 By making our C<left> and C<right> attributes C<lazy>, we avoid this
145 problem. If the attribute has a value when it is read, the default is
146 never executed at all.
148 We still have one last bit of behavior to add. The autogenerated
149 C<right> and C<left> accessors are not quite correct. When one of
150 these is set, we want to make sure that we update the parent of the
151 C<left> or C<right> attribute's tree.
153 We could write our own accessors, but then why use Moose at all?
154 Instead, we use method modifiers:
156 before 'right', 'left' => sub {
157 my ( $self, $tree ) = @_;
159 confess "You cannot insert a tree which already has a parent"
160 if $tree->has_parent;
161 $tree->parent($self);
165 This is a C<before> modifier, just like we saw in the second recipe,
166 but with two slight differences. First, we are applying the modifier
167 to more than one method at a time, because both C<left> and C<right>
168 attributes need the same behavior. The other difference is that we are
169 not wrapping an inherited method, but rather a method from our own
170 local class. Wrapping local methods is no different, the only
171 requirement is that the wrappee must exist before the wrapper is
172 defined (after all, you cannot wrap something which doesn't exist,
175 We could also get the same outcome by using an attribute trigger. A
176 trigger is fired whenever the attribute is I<set>. See
177 L<Moose::Manual::Attributes/Triggers> for more information about
180 As with all the other recipes, B<BinaryTree> can be used just like any
181 other Perl 5 class. A more detailed example of its usage can be found
182 in F<t/000_recipes/003_recipe.t>.
186 This recipe introduced several of Moose's advanced features. We hope
187 that this inspires you to think of other ways these features can be
188 used to simplify your code.
196 Weak references are tricky things, and should be used sparingly and
197 appropriately (such as in the case of circular refs). If you are not
198 careful, attribute values could disappear "mysteriously" because
199 Perl's reference counting garbage collector has gone and removed the
200 item you are weak-referencing.
202 In short, don't use them unless you know what you are doing :)
206 You I<can> use the C<default> option without the C<lazy> option if you
207 like, as we showed in the second recipe.
209 Also, you can use C<builder> instead of C<default>. See
210 L<Moose::Cookbook::Basics::Recipe9> for details.
216 Stevan Little E<lt>stevan@iinteractive.comE<gt>
218 Dave Rolsky E<lt>autarch@urth.orgE<gt>
220 =head1 COPYRIGHT AND LICENSE
222 Copyright 2006-2009 by Infinity Interactive, Inc.
224 L<http://www.iinteractive.com>
226 This library is free software; you can redistribute it and/or modify
227 it under the same terms as Perl itself.