adding more tests to the binary tree recipe, and adding the RoleName type constraint
[gitmo/Moose.git] / lib / Moose / Cookbook / Basics / Recipe3.pod
CommitLineData
471c4f09 1
2=pod
3
4=head1 NAME
5
021b8139 6Moose::Cookbook::Basics::Recipe3 - A lazy B<BinaryTree> example
471c4f09 7
8=head1 SYNOPSIS
9
10 package BinaryTree;
471c4f09 11 use Moose;
c765b254 12
13 has 'node' => ( is => 'rw', isa => 'Any' );
14
471c4f09 15 has 'parent' => (
8597d950 16 is => 'rw',
c765b254 17 isa => 'BinaryTree',
471c4f09 18 predicate => 'has_parent',
8597d950 19 weak_ref => 1,
471c4f09 20 );
c765b254 21
471c4f09 22 has 'left' => (
c765b254 23 is => 'rw',
24 isa => 'BinaryTree',
25 predicate => 'has_left',
7c6cacb4 26 lazy => 1,
c765b254 27 default => sub { BinaryTree->new( parent => $_[0] ) },
471c4f09 28 );
c765b254 29
471c4f09 30 has 'right' => (
c765b254 31 is => 'rw',
32 isa => 'BinaryTree',
33 predicate => 'has_right',
34 lazy => 1,
35 default => sub { BinaryTree->new( parent => $_[0] ) },
471c4f09 36 );
c765b254 37
471c4f09 38 before 'right', 'left' => sub {
c765b254 39 my ( $self, $tree ) = @_;
f0cac16f 40 if (defined $tree) {
41 confess "You cannot insert a tree which already has a parent"
42 if $tree->has_parent;
43 $tree->parent($self);
44 }
471c4f09 45 };
46
47=head1 DESCRIPTION
48
f6f9ec6a 49This recipe shows how various advanced attribute features can be used
50to create complex and powerful behaviors.
8597d950 51
f6f9ec6a 52The example class is a classic binary tree. Each node in the tree is
53itself an instance of C<BinaryTree>. It has a C<node>, which holds
54some arbitrary value. It has C<right> and C<left> attributes, which
55refer to its child trees, and a C<parent>.
8597d950 56
f6f9ec6a 57Let's take a look at the C<node> attribute:
8597d950 58
c765b254 59 has 'node' => ( is => 'rw', isa => 'Any' );
8597d950 60
f6f9ec6a 61Moose generates a read-write accessor for this attribute. The type
62constraint is C<Any>, which means literally means it can contain
63anything.
455ca293 64
f6f9ec6a 65We could have left out the C<isa> option, but in this case, we are
19320607 66including it for the benefit of other programmers, not the computer.
f6f9ec6a 67
68Next, let's move on to the C<parent> attribute:
8597d950 69
70 has 'parent' => (
71 is => 'rw',
c765b254 72 isa => 'BinaryTree',
8597d950 73 predicate => 'has_parent',
74 weak_ref => 1,
75 );
76
f6f9ec6a 77Again, we have a read-write accessor. This time, the C<isa> option
78says that this attribute must always be an instance of
79C<BinaryTree>. In the second recipe, we saw that every time we create
80a Moose-based class, we also get a corresponding class type
81constraint.
8597d950 82
f6f9ec6a 83The C<predicate> option is new. It creates a method which can be used
84to check whether or not a given attribute has been initialized. In
85this case, the method is named C<has_parent>.
8597d950 86
f6f9ec6a 87This brings us to our last attribute option, C<weak_ref>. Since
88C<parent> is a circular reference (the tree in C<parent> should
89already have a reference to this one, in its C<left> or C<right>
90attribute), we want to make sure that we weaken the reference to avoid
91memory leaks. If C<weak_ref> is true, it alters the accessor function
92so that the reference is weakened when it is set.
8597d950 93
f6f9ec6a 94Finally, we have the the C<left> and C<right> attributes. They are
95essentially identical except for their names, so we'll just look at
96C<left>:
8597d950 97
98 has 'left' => (
c765b254 99 is => 'rw',
100 isa => 'BinaryTree',
101 predicate => 'has_left',
8597d950 102 lazy => 1,
c765b254 103 default => sub { BinaryTree->new( parent => $_[0] ) },
8597d950 104 );
105
f6f9ec6a 106There are two new options here, C<lazy> and C<default>. These two
107options are linked, and in fact you cannot have a C<lazy> attribute
108unless it has a C<default> (or a C<builder>, but we'll cover that
109later). If you try to make an attribute lazy without a default, class
110creation will fail with an exception. (2)
111
112In the second recipe the B<BankAccount>'s C<balance> attribute had a
113default value of C<0>. Given a non-reference, Perl copies the
114I<value>. However, given a reference, it does not do a deep clone,
115instead simply copying the reference. If you just specified a simply
116reference for a default, Perl would create it once and it would be
117shared by all objects with that attribute.
8597d950 118
f6f9ec6a 119As a workaround, we use an anonymous subroutine to generate a new
120reference every time the default is called.
8597d950 121
f6f9ec6a 122 has 'foo' => ( is => 'rw', default => sub { [] } );
123
124In fact, using a non-subroutine reference as a default is illegal in Moose.
8597d950 125
c765b254 126 has 'foo' => ( is => 'rw', default => [] );
8597d950 127
f6f9ec6a 128This will blow up, so don't do it.
8597d950 129
f6f9ec6a 130You'll notice that we use C<$_[0]> in our default sub. When the
131default subroutine is executed, it is called as a method on the
132object.
133
134In our case, we're making a new C<BinaryTree> object in our default,
135with the current tree as the parent.
136
19320607 137Normally, when an object is instantiated, any defaults are evaluated
f6f9ec6a 138immediately. With our C<BinaryTree> class, this would be a big
139problem! We'd create the first object, which would immediately try to
140populate its C<left> and C<right> attributes, which would create a new
141C<BinaryTree>, which would populate I<its> C<left> and C<right>
142slots. Kaboom!
143
144By making our C<left> and C<right> attributes C<lazy>, we avoid this
145problem. If the attribute has a value when it is read, the default is
146never executed at all.
147
148We still have one last bit of behavior to add. The autogenerated
149C<right> and C<left> accessors are not quite correct. When one of
150these is set, we want to make sure that we update the parent of the
151C<left> or C<right> attribute's tree.
8597d950 152
f6f9ec6a 153We could write our own accessors, but then why use Moose at all?
154Instead, we use method modifiers:
c765b254 155
8597d950 156 before 'right', 'left' => sub {
c765b254 157 my ( $self, $tree ) = @_;
f0cac16f 158 if (defined $tree) {
159 confess "You cannot insert a tree which already has a parent"
160 if $tree->has_parent;
161 $tree->parent($self);
162 }
8597d950 163 };
164
f6f9ec6a 165This is a C<before> modifier, just like we saw in the second recipe,
166but with two slight differences. First, we are applying the modifier
167to more than one method at a time, because both C<left> and C<right>
168attributes need the same behavior. The other difference is that we are
169not wrapping an inherited method, but rather a method from our own
170local class. Wrapping local methods is no different, the only
171requirement is that the wrappee must exist before the wrapper is
172defined (after all, you cannot wrap something which doesn't exist,
455ca293 173right?).
8597d950 174
f6f9ec6a 175As with all the other recipes, B<BinaryTree> can be used just like any
176other Perl 5 class. A more detailed example of its usage can be found
177in F<t/000_recipes/003_recipe.t>.
8597d950 178
179=head1 CONCLUSION
180
f6f9ec6a 181This recipe introduced several of Moose's advanced features. We hope
182that this inspires you to think of other ways these features can be
183used to simplify your code.
e08c54f5 184
8597d950 185=head1 FOOTNOTES
186
187=over 4
188
189=item (1)
190
f6f9ec6a 191Weak references are tricky things, and should be used sparingly and
192appropriately (such as in the case of circular refs). If you are not
193careful, attribute values could disappear "mysteriously" because
194Perl's reference counting garbage collector has gone and removed the
195item you are weak-referencing.
8597d950 196
197In short, don't use them unless you know what you are doing :)
198
199=item (2)
200
f6f9ec6a 201You I<can> use the C<default> option without the C<lazy> option if you
202like, as we showed in the second recipe.
8597d950 203
f6f9ec6a 204Also, you can use C<builder> instead of C<default>. See
021b8139 205L<Moose::Cookbook::Basics::Recipe9> for details.
ceb8945d 206
8597d950 207=back
208
8c3d5c88 209=head1 AUTHORS
471c4f09 210
211Stevan Little E<lt>stevan@iinteractive.comE<gt>
212
8c3d5c88 213Dave Rolsky E<lt>autarch@urth.orgE<gt>
214
471c4f09 215=head1 COPYRIGHT AND LICENSE
216
2840a3b2 217Copyright 2006-2009 by Infinity Interactive, Inc.
471c4f09 218
219L<http://www.iinteractive.com>
220
221This library is free software; you can redistribute it and/or modify
222it under the same terms as Perl itself.
223
f7522f24 224=cut