Made an editorial pass over basics recipe 3
[gitmo/Moose.git] / lib / Moose / Cookbook / Basics / Recipe3.pod
1
2 =pod
3
4 =head1 NAME
5
6 Moose::Cookbook::Basics::Recipe3 - A lazy B<BinaryTree> example
7
8 =head1 SYNOPSIS
9
10   package BinaryTree;
11   use Moose;
12
13   has 'node' => ( is => 'rw', isa => 'Any' );
14
15   has 'parent' => (
16       is        => 'rw',
17       isa       => 'BinaryTree',
18       predicate => 'has_parent',
19       weak_ref  => 1,
20   );
21
22   has 'left' => (
23       is        => 'rw',
24       isa       => 'BinaryTree',
25       predicate => 'has_left',
26       lazy      => 1,
27       default   => sub { BinaryTree->new( parent => $_[0] ) },
28   );
29
30   has 'right' => (
31       is        => 'rw',
32       isa       => 'BinaryTree',
33       predicate => 'has_right',
34       lazy      => 1,
35       default   => sub { BinaryTree->new( parent => $_[0] ) },
36   );
37
38   before 'right', 'left' => sub {
39       my ( $self, $tree ) = @_;
40       $tree->parent($self) if defined $tree;
41   };
42
43 =head1 DESCRIPTION
44
45 This recipe shows how various advanced attribute features can be used
46 to create complex and powerful behaviors.
47
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>.
52
53 Let's take a look at the C<node> attribute:
54
55   has 'node' => ( is => 'rw', isa => 'Any' );
56
57 Moose generates a read-write accessor for this attribute. The type
58 constraint is C<Any>, which means literally means it can contain
59 anything.
60
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.
63
64 Next, let's move on to the C<parent> attribute:
65
66   has 'parent' => (
67       is        => 'rw',
68       isa       => 'BinaryTree',
69       predicate => 'has_parent',
70       weak_ref  => 1,
71   );
72
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
77 constraint.
78
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>.
82
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.
89
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
92 C<left>:
93
94   has 'left' => (
95       is        => 'rw',
96       isa       => 'BinaryTree',
97       predicate => 'has_left',
98       lazy      => 1,
99       default   => sub { BinaryTree->new( parent => $_[0] ) },
100   );
101
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)
107
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.
114
115 As a workaround, we use an anonymous subroutine to generate a new
116 reference every time the default is called.
117
118   has 'foo' => ( is => 'rw', default => sub { [] } );
119
120 In fact, using a non-subroutine reference as a default is illegal in Moose.
121
122   has 'foo' => ( is => 'rw', default => [] );
123
124 This will blow up, so don't do it.
125
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
128 object.
129
130 In our case, we're making a new C<BinaryTree> object in our default,
131 with the current tree as the parent.
132
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>
138 slots. Kaboom!
139
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.
143
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.
148
149 We could write our own accessors, but then why use Moose at all?
150 Instead, we use method modifiers:
151
152   before 'right', 'left' => sub {
153       my ( $self, $tree ) = @_;
154       $tree->parent($self) if defined $tree;
155   };
156
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,
165 right?).
166
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>.
170
171 =head1 CONCLUSION
172
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.
176
177 =head1 FOOTNOTES
178
179 =over 4
180
181 =item (1)
182
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.
188
189 In short, don't use them unless you know what you are doing :)
190
191 =item (2)
192
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.
195
196 Also, you can use C<builder> instead of C<default>. See
197 L<Moose::Cookbook::Basics::Recipe9> for details.
198
199 =back
200
201 =head1 AUTHOR
202
203 Stevan Little E<lt>stevan@iinteractive.comE<gt>
204
205 =head1 COPYRIGHT AND LICENSE
206
207 Copyright 2006-2009 by Infinity Interactive, Inc.
208
209 L<http://www.iinteractive.com>
210
211 This library is free software; you can redistribute it and/or modify
212 it under the same terms as Perl itself.
213
214 =cut