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 ) = @_;
40 $tree->parent($self) if defined $tree;
45 This recipe shows how various advanced attribute features can be used
46 to create complex and powerful behaviors.
48 The example class is a classic binary tree. Each node in the tree is
49 itself an instance of C<BinaryTree>. It has a C<node>, which holds
50 some arbitrary value. It has C<right> and C<left> attributes, which
51 refer to its child trees, and a C<parent>.
53 Let's take a look at the C<node> attribute:
55 has 'node' => ( is => 'rw', isa => 'Any' );
57 Moose generates a read-write accessor for this attribute. The type
58 constraint is C<Any>, which means literally means it can contain
61 We could have left out the C<isa> option, but in this case, we are
62 including ir for the benefit of other programmers, not the computer.
64 Next, let's move on to the C<parent> attribute:
69 predicate => 'has_parent',
73 Again, we have a read-write accessor. This time, the C<isa> option
74 says that this attribute must always be an instance of
75 C<BinaryTree>. In the second recipe, we saw that every time we create
76 a Moose-based class, we also get a corresponding class type
79 The C<predicate> option is new. It creates a method which can be used
80 to check whether or not a given attribute has been initialized. In
81 this case, the method is named C<has_parent>.
83 This brings us to our last attribute option, C<weak_ref>. Since
84 C<parent> is a circular reference (the tree in C<parent> should
85 already have a reference to this one, in its C<left> or C<right>
86 attribute), we want to make sure that we weaken the reference to avoid
87 memory leaks. If C<weak_ref> is true, it alters the accessor function
88 so that the reference is weakened when it is set.
90 Finally, we have the the C<left> and C<right> attributes. They are
91 essentially identical except for their names, so we'll just look at
97 predicate => 'has_left',
99 default => sub { BinaryTree->new( parent => $_[0] ) },
102 There are two new options here, C<lazy> and C<default>. These two
103 options are linked, and in fact you cannot have a C<lazy> attribute
104 unless it has a C<default> (or a C<builder>, but we'll cover that
105 later). If you try to make an attribute lazy without a default, class
106 creation will fail with an exception. (2)
108 In the second recipe the B<BankAccount>'s C<balance> attribute had a
109 default value of C<0>. Given a non-reference, Perl copies the
110 I<value>. However, given a reference, it does not do a deep clone,
111 instead simply copying the reference. If you just specified a simply
112 reference for a default, Perl would create it once and it would be
113 shared by all objects with that attribute.
115 As a workaround, we use an anonymous subroutine to generate a new
116 reference every time the default is called.
118 has 'foo' => ( is => 'rw', default => sub { [] } );
120 In fact, using a non-subroutine reference as a default is illegal in Moose.
122 has 'foo' => ( is => 'rw', default => [] );
124 This will blow up, so don't do it.
126 You'll notice that we use C<$_[0]> in our default sub. When the
127 default subroutine is executed, it is called as a method on the
130 In our case, we're making a new C<BinaryTree> object in our default,
131 with the current tree as the parent.
133 Normally, when an object is instantiated, any defaults are evaluted
134 immediately. With our C<BinaryTree> class, this would be a big
135 problem! We'd create the first object, which would immediately try to
136 populate its C<left> and C<right> attributes, which would create a new
137 C<BinaryTree>, which would populate I<its> C<left> and C<right>
140 By making our C<left> and C<right> attributes C<lazy>, we avoid this
141 problem. If the attribute has a value when it is read, the default is
142 never executed at all.
144 We still have one last bit of behavior to add. The autogenerated
145 C<right> and C<left> accessors are not quite correct. When one of
146 these is set, we want to make sure that we update the parent of the
147 C<left> or C<right> attribute's tree.
149 We could write our own accessors, but then why use Moose at all?
150 Instead, we use method modifiers:
152 before 'right', 'left' => sub {
153 my ( $self, $tree ) = @_;
154 $tree->parent($self) if defined $tree;
157 This is a C<before> modifier, just like we saw in the second recipe,
158 but with two slight differences. First, we are applying the modifier
159 to more than one method at a time, because both C<left> and C<right>
160 attributes need the same behavior. The other difference is that we are
161 not wrapping an inherited method, but rather a method from our own
162 local class. Wrapping local methods is no different, the only
163 requirement is that the wrappee must exist before the wrapper is
164 defined (after all, you cannot wrap something which doesn't exist,
167 As with all the other recipes, B<BinaryTree> can be used just like any
168 other Perl 5 class. A more detailed example of its usage can be found
169 in F<t/000_recipes/003_recipe.t>.
173 This recipe introduced several of Moose's advanced features. We hope
174 that this inspires you to think of other ways these features can be
175 used to simplify your code.
183 Weak references are tricky things, and should be used sparingly and
184 appropriately (such as in the case of circular refs). If you are not
185 careful, attribute values could disappear "mysteriously" because
186 Perl's reference counting garbage collector has gone and removed the
187 item you are weak-referencing.
189 In short, don't use them unless you know what you are doing :)
193 You I<can> use the C<default> option without the C<lazy> option if you
194 like, as we showed in the second recipe.
196 Also, you can use C<builder> instead of C<default>. See
197 L<Moose::Cookbook::Basics::Recipe9> for details.
203 Stevan Little E<lt>stevan@iinteractive.comE<gt>
205 Dave Rolsky E<lt>autarch@urth.orgE<gt>
207 =head1 COPYRIGHT AND LICENSE
209 Copyright 2006-2009 by Infinity Interactive, Inc.
211 L<http://www.iinteractive.com>
213 This library is free software; you can redistribute it and/or modify
214 it under the same terms as Perl itself.