X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FCookbook%2FRecipe3.pod;h=9d49f0c41ad3573e79d80a05daf6beb4454c2c6b;hb=dec63b1ac3f931810b2bb917f49f0b3a158b712f;hp=19e7d0e556c192f1ec1d5cb90596fa7367f310df;hpb=e08c54f595734e63385e2a4a758b9655c302bf41;p=gitmo%2FMoose.git diff --git a/lib/Moose/Cookbook/Recipe3.pod b/lib/Moose/Cookbook/Recipe3.pod index 19e7d0e..9d49f0c 100644 --- a/lib/Moose/Cookbook/Recipe3.pod +++ b/lib/Moose/Cookbook/Recipe3.pod @@ -8,8 +8,6 @@ Moose::Cookbook::Recipe3 - A lazy B example =head1 SYNOPSIS package BinaryTree; - use strict; - use warnings; use Moose; has 'node' => (is => 'rw', isa => 'Any'); @@ -50,27 +48,27 @@ complex behaviors. The class in this recipe is a classic binary tree, each node in the tree is represented by an instance of the B class. Each -instance has a C slot to hold an abitrary value, a C +instance has a C slot to hold an arbitrary value, a C slot to hold the right node, a C slot to hold the left node, and finally a C slot to hold a reference back up the tree. -Now, let's start with the code, our first attribute is the C +Now, let's start with the code. Our first attribute is the C slot, defined as such: has 'node' => (is => 'rw', isa => 'Any'); -If you recall from the previous recipies, this slot will have a -read/write accessor generated for it, and has a type constraint on it. -The new item here is the type constraint of C. In the type -constraint heirarchy in L, the C -constraint is the "root" of the hierarchy. It means exactly what it -says, it allows anything to pass. Now, you could just as easily have -left out the C, left the C slot unconstrained and gotten the -same behavior. But here, we are really including the type constraint -for the benefit of other programmers, not the computer. It makes -clear my intent that the C can be of any type, and that the -class is a polymorphic container. Next, lets move onto the C -slot. +If you recall from the previous recipes, this slot will have a read/write +accessor generated for it, and has a type constraint on it. The new item here is +the type constraint of C. C is the "root" of the +L type hierarchy. It means exactly what it says: +I value passes the constraint. Now, you could just as easily have left out +the C, leaving the C slot unconstrained and retaining this +behavior. But in this case, we are really including the type constraint for the +benefit of other programmers, not the computer. It makes clear my intent that +the C attribute can be of any type, and that the class is a polymorphic +container. + +Next, let's move on to the C slot: has 'parent' => ( is => 'rw', @@ -79,30 +77,27 @@ slot. weak_ref => 1, ); -As you already know from reading the previous recipes, this code -tells you that C gets a read/write accessor and is constrained -to only accept instances of B. You will of course remember -from the second recipe that the C type constraint is -automatically created for us by Moose. +As you already know, this code tells you that C gets a read/write +accessor and is constrained to only accept instances of B. You will +of course remember from the second recipe that the C type constraint +is automatically created for us by Moose. -The next attribute option is new though, the C option. -This option creates a method, which can be used to check to see if -a given slot (in this case C) has a defined value in it. In +The next attribute option is new, though: the C option. +This option creates a method which can be used to check whether +a given slot (in this case C) has been initialized. In this case it will create a method called C. Quite simple, -and also quite handy too. +and quite handy too. -This brings us to our last attribute, and also a new one. Since the -C is a circular reference (the tree in C should -already have a reference in either it's C or C nodes), -we want to make sure that it is also a weakened reference to avoid -memory leaks. The C attribute option will do just that, -C simply takes a boolean value (C<1> or C<0>) and it will -then add the extra capability to the accessor function to weaken -the reference of any value stored in the C slot (1). +This brings us to our last attribute option, also a new one. Since C is +a circular reference (the tree in C should already have a reference to +this one, in its C or C node), we want to make sure that it is also +a weakened reference to avoid memory leaks. The C attribute option +will do just that, C simply takes a boolean value (C<1> or C<0>) and +then alters the accessor function to weaken the reference to any value stored in +the C slot (1). -Now, onto the C and C attributes. They are essentially -the same things, only with different names, so I will just describe -one here. +Now, onto the C and C attributes. They are essentially identical, +save for different names, so I will just describe one here: has 'left' => ( is => 'rw', @@ -112,11 +107,10 @@ one here. default => sub { BinaryTree->new(parent => $_[0]) }, ); -You already know what the C, C and C options -do, but now we have two more new options. These two options are -actually linked together, in fact, you cannot use the C -option unless you have set the C option. The class -creation will fail with an exception (2). +You already know what the C, C and C options do, but now we +have two new options. These two options are actually linked together, in fact: +you cannot use the C option unless you have set the C option. +Class creation will fail with an exception (2). Before I go into detail about how C works, let me first explain how C works, and in particular why it is wrapped @@ -125,32 +119,28 @@ in a CODE ref. In the second recipe the B's C slot had a default value of C<0>. Since Perl will copy strings and numbers by value, this was all we had to say. But for any other item -(ARRAY ref, HASH ref, object instance, etc) Perl will copy by -reference. This means that if I were to do this: +(ARRAY ref, HASH ref, object instance, etc) you would need to +wrap it in a CODE reference, so this: has 'foo' => (is => 'rw', default => []); -Every single instance of that class would get a pointer to the -same ARRAY ref in their C slot. This is almost certainly -B the behavior you intended. So, the solution is to wrap -these defaults into an anon-sub, like so: +is actually illegal in Moose. Instead, what you really want is this: has 'foo' => (is => 'rw', default => sub { [] }); -This assures that each instance of this class will get it's own -ARRAY ref in the C slot. +This ensures that each instance of this class will get its own ARRAY ref in the +C slot. -One other feature of the sub ref version of the C option -is that when the subroutine is executed (to get back the expected -default value), we also pass in the instance where the slot will -be stored. This added feature can come in quite handy at times, as -is illustrated above, with this code: +One other feature of the CODE ref version of the C option is that when +the subroutine is executed (to get the default value), we pass in the instance +where the slot will be stored. This can come in quite handy at times, as +illustrated above, with this code: default => sub { BinaryTree->new(parent => $_[0]) }, -The default value being generated is a new C instance -for the C (or C) slot. Here we set up the parental -relationship by passing the current instance to the constructor. +The default value being generated is a new C instance for the +C (or C) slot. Here we set up the correct relationship by passing +the current instance as the C argument to the constructor. Now, before we go on to the C option, I want you to think for a moment. When an instance of this class is created, and the @@ -164,44 +154,42 @@ exhausted all available memory on your machine. This is, of course, not good :) -Which brings us to the C attribute option. The C option -does just what it says. It lazily initializes the slot within the -instance. This means that it waits till the I last possible -moment to populate the slot. This means that if you, the user, write -to the slot, everything happens as normal and what you pass in is stored. -However, if you I the slot, then at that I moment (and no -sooner), the slot will be populated with the value of the C -option. +Which brings us to the C attribute option. The C option does just +what it says: it lazily initializes the slot within the instance. This means +that it waits till absolutely the I possible moment to populate the +slot. So if you, the user, store a value in the slot, everything works normally, +and what you pass in is stored. However, if you I the slot I +storing a value in it, then at that I moment (and no sooner), the slot +will be populated with the value of the C option. This option is what allows the B class to instantiate objects without fear of the I mentioned earlier. -So, we have described a quite complex set of behaviors here, and not -one method had to be written. But wait, we can't get away that -easily. The autogenerated C and C accessors are not -completely correct. They will not install the parental relationships -that we need. We could write our own accessors, but that would require -us to implement all those features we got automatically (the type -constraint, the lazy initialization, etc). So instead we use the -method modifiers again. +So, we have described a quite complex set of behaviors here, and not one method +had to be written. But wait, we aren't quite done yet; the autogenerated +C and C accessors are not completely correct. They will not install +the parental relationships that we need. We could write our own accessors, but +that would require us to implement all those features we got automatically (type +constraints, lazy initialization, and so on). Instead, we use method modifiers +again: before 'right', 'left' => sub { my ($self, $tree) = @_; $tree->parent($self) if defined $tree; }; -This is a C modifier, just like we saw in the second recipe, -but with two slight differences. First, we are applying this to more -than one method at a time. Since both the C and C methods -need the same feature, it makes sense. The second difference is that -we are not wrapping an inherited method anymore, but instead a method -of our own local class. Wrapping local methods is no different, the -only requirement is that the wrappee be created before the wrapper -(after all, you cannot wrap something which doesn't exist right?). +This is a C modifier, just like we saw in the second recipe, but with +two slight differences. First, we are applying this to more than one method at a +time. Since both the C and C methods need the same feature, it +makes sense. The second difference is that we are not wrapping an inherited +method anymore, but instead a method of our own local class. Wrapping local +methods is no different, the only requirement is that the wrappee be created +before the wrapper (after all, you cannot wrap something which doesn't exist, +right?). Now, as with all the other recipes, you can go about using -B like any other Perl 5 class. A more detailed example of +B like any other Perl 5 class. A more detailed example of its usage can be found in F. =head1 CONCLUSION @@ -239,7 +227,7 @@ Stevan Little Estevan@iinteractive.comE =head1 COPYRIGHT AND LICENSE -Copyright 2006 by Infinity Interactive, Inc. +Copyright 2006-2008 by Infinity Interactive, Inc. L