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