1Moose::Cookbook::BasicsUM:so:eoBrsienC:ao:rnCytoTrorikebbeuo_toAektd:t:rPBieabrsulitceDsFo:ec:auBtmiuenrnaetrsay(tT3ir)oene_AttributeFeatures(3)
2
3
4

NAME

6       Moose::Cookbook::Basics::BinaryTree_AttributeFeatures - Demonstrates
7       various attribute features including lazy, predicates, weak refs, and
8       more
9

VERSION

11       version 2.2203
12

SYNOPSIS

14         package BinaryTree;
15         use Moose;
16
17         has 'node' => ( is => 'rw', isa => 'Any' );
18
19         has 'parent' => (
20             is        => 'rw',
21             isa       => 'BinaryTree',
22             predicate => 'has_parent',
23             weak_ref  => 1,
24         );
25
26         has 'left' => (
27             is        => 'rw',
28             isa       => 'BinaryTree',
29             predicate => 'has_left',
30             lazy      => 1,
31             default   => sub { BinaryTree->new( parent => $_[0] ) },
32             trigger   => \&_set_parent_for_child
33         );
34
35         has 'right' => (
36             is        => 'rw',
37             isa       => 'BinaryTree',
38             predicate => 'has_right',
39             lazy      => 1,
40             default   => sub { BinaryTree->new( parent => $_[0] ) },
41             trigger   => \&_set_parent_for_child
42         );
43
44         sub _set_parent_for_child {
45             my ( $self, $child ) = @_;
46
47             confess "You cannot insert a tree which already has a parent"
48                 if $child->has_parent;
49
50             $child->parent($self);
51         }
52

DESCRIPTION

54       This recipe shows how various advanced attribute features can be used
55       to create complex and powerful behaviors. In particular, we introduce a
56       number of new attribute options, including "predicate", "lazy", and
57       "trigger".
58
59       The example class is a classic binary tree. Each node in the tree is
60       itself an instance of "BinaryTree". It has a "node", which holds some
61       arbitrary value. It has "right" and "left" attributes, which refer to
62       its child trees, and a "parent".
63
64       Let's take a look at the "node" attribute:
65
66         has 'node' => ( is => 'rw', isa => 'Any' );
67
68       Moose generates a read-write accessor for this attribute. The type
69       constraint is "Any", which literally means it can contain anything.
70
71       We could have left out the "isa" option, but in this case, we are
72       including it for the benefit of other programmers, not the computer.
73
74       Next, let's move on to the "parent" attribute:
75
76         has 'parent' => (
77             is        => 'rw',
78             isa       => 'BinaryTree',
79             predicate => 'has_parent',
80             weak_ref  => 1,
81         );
82
83       Again, we have a read-write accessor. This time, the "isa" option says
84       that this attribute must always be an instance of "BinaryTree". In the
85       second recipe, we saw that every time we create a Moose-based class, we
86       also get a corresponding class type constraint.
87
88       The "predicate" option is new. It creates a method which can be used to
89       check whether or not a given attribute has been initialized. In this
90       case, the method is named "has_parent".
91
92       This brings us to our last attribute option, "weak_ref". Since "parent"
93       is a circular reference (the tree in "parent" should already have a
94       reference to this one, in its "left" or "right" attribute), we want to
95       make sure that we weaken the reference to avoid memory leaks. If
96       "weak_ref" is true, it alters the accessor function so that the
97       reference is weakened when it is set.
98
99       Finally, we have the "left" and "right" attributes. They are
100       essentially identical except for their names, so we'll just look at
101       "left":
102
103         has 'left' => (
104             is        => 'rw',
105             isa       => 'BinaryTree',
106             predicate => 'has_left',
107             lazy      => 1,
108             default   => sub { BinaryTree->new( parent => $_[0] ) },
109             trigger   => \&_set_parent_for_child
110         );
111
112       There are three new options here, "lazy", "default", and "trigger". The
113       "lazy" and "default" options are linked.  In fact, you cannot have a
114       "lazy" attribute unless it has a "default" (or a "builder", but we'll
115       cover that later). If you try to make an attribute lazy without a
116       default, class creation will fail with an exception. (2)
117
118       In the second recipe the BankAccount's "balance" attribute had a
119       default value of 0. Given a non-reference, Perl copies the value.
120       However, given a reference, it does not do a deep clone, instead simply
121       copying the reference. If you just specified a simple reference for a
122       default, Perl would create it once and it would be shared by all
123       objects with that attribute.
124
125       As a workaround, we use an anonymous subroutine to generate a new
126       reference every time the default is called.
127
128         has 'foo' => ( is => 'rw', default => sub { [] } );
129
130       In fact, using a non-subroutine reference as a default is illegal in
131       Moose.
132
133         # will fail
134         has 'foo' => ( is => 'rw', default => [] );
135
136       This will blow up, so don't do it.
137
138       You'll notice that we use $_[0] in our default sub. When the default
139       subroutine is executed, it is called as a method on the object.
140
141       In our case, we're making a new "BinaryTree" object in our default,
142       with the current tree as the parent.
143
144       Normally, when an object is instantiated, any defaults are evaluated
145       immediately. With our "BinaryTree" class, this would be a big problem!
146       We'd create the first object, which would immediately try to populate
147       its "left" and "right" attributes, which would create a new
148       "BinaryTree", which would populate its "left" and "right" slots.
149       Kaboom!
150
151       By making our "left" and "right" attributes "lazy", we avoid this
152       problem. If the attribute has a value when it is read, the default is
153       never executed at all.
154
155       We still have one last bit of behavior to add. The autogenerated
156       "right" and "left" accessors are not quite correct. When one of these
157       is set, we want to make sure that we update the parent of the "left" or
158       "right" attribute's tree.
159
160       We could write our own accessors, but then why use Moose at all?
161       Instead, we use a "trigger". A "trigger" accepts a subroutine
162       reference, which will be called as a method whenever the attribute is
163       set. This can happen both during object construction or later by
164       passing a new object to the attribute's accessor method. However, it is
165       not called when a value is provided by a "default" or "builder".
166
167         sub _set_parent_for_child {
168             my ( $self, $child ) = @_;
169
170             confess "You cannot insert a tree which already has a parent"
171                 if $child->has_parent;
172
173             $child->parent($self);
174         }
175
176       This trigger does two things. First, it ensures that the new child node
177       does not already have a parent. This is done for the sake of
178       simplifying the example. If we wanted to be more clever, we would
179       remove the child from its old parent tree and add it to the new one.
180
181       If the child has no parent, we will add it to the current tree, and we
182       ensure that is has the correct value for its "parent" attribute.
183
184       As with all the other recipes, BinaryTree can be used just like any
185       other Perl 5 class. A more detailed example of its usage can be found
186       in t/recipes/basics_binarytree_attributefeatures.t.
187

CONCLUSION

189       This recipe introduced several of Moose's advanced features. We hope
190       that this inspires you to think of other ways these features can be
191       used to simplify your code.
192

FOOTNOTES

194       (1) Weak references are tricky things, and should be used sparingly and
195           appropriately (such as in the case of circular refs). If you are
196           not careful, attribute values could disappear "mysteriously"
197           because Perl's reference counting garbage collector has gone and
198           removed the item you are weak-referencing.
199
200           In short, don't use them unless you know what you are doing :)
201
202       (2) You can use the "default" option without the "lazy" option if you
203           like, as we showed in the second recipe.
204
205           Also, you can use "builder" instead of "default". See
206           Moose::Cookbook::Basics::BinaryTree_BuilderAndLazyBuild for
207           details.
208

AUTHORS

210       •   Stevan Little <stevan@cpan.org>
211
212       •   Dave Rolsky <autarch@urth.org>
213
214       •   Jesse Luehrs <doy@cpan.org>
215
216       •   Shawn M Moore <sartak@cpan.org>
217
218       •   יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
219
220       •   Karen Etheridge <ether@cpan.org>
221
222       •   Florian Ragwitz <rafl@debian.org>
223
224       •   Hans Dieter Pearcey <hdp@cpan.org>
225
226       •   Chris Prather <chris@prather.org>
227
228       •   Matt S Trout <mstrout@cpan.org>
229
231       This software is copyright (c) 2006 by Infinity Interactive, Inc.
232
233       This is free software; you can redistribute it and/or modify it under
234       the same terms as the Perl 5 programming language system itself.
235
236
237
238perl v5.36.0          Moose::Cookb2o0o2k3:-:0B2a-s0i6cs::BinaryTree_AttributeFeatures(3)
Impressum