Target Audience: This series is pitched at developers interested in Object Oriented Design Patterns using the Moose framework in Perl. I cover the examples from the Head First Design Patterns book, replicating Java implementation in Moose. You need to obtain a copy of the book, which is not hard to come by.
Don't mess with the Moose! (Notes so you don't.)
An object, as the old saying goes, has data and methods. Data are stuffed in various slots and, to make a long story short, Moose provides 'attributes' to qualify a slot. Qualify - how? Well, for starters, what if you want a 'read-only' slot? That is achieved by setting the 'is' attribute to 'ro' - thus ensuring that Moose generates a getter (or accessor) for the method and omits the setter (or mutator).
Attributes are one cool feature of the Moose. They are the muscle and sinew. And the case-studies below illustrate some of the power.
Case of the Trigger-Happy Moose
The 'trigger' is a subroutine reference set upon a slot, so that the subroutine is invoked whenever the slot is set. This can happen both during object construction or later by passing a new object to the attribute's accessor method. However, it is not called when a value is provided via a 'default' or 'builder'.
The Moose Defaults
You do not need a constructor for a Moose class. Instead, use the 'default' attibute set upon each slot. The 'default' attribute holds a subroutine reference, the return of which is stuffed into the slot.
For self-reference in 'default', use $_[0] in the sub. When the sub is executed, it is invoked as a method on the object.
And therein lies the rub! Remember, remember (the 5th of November) .. it is the returned object or value that is stuffed into the slot. Be sure that what the sub returns is indeed what you want stuffed in the slot! There's many a slip twixt cup and lip (or slot and sub) .. many a Moose has been waylaid trying to set the slot explicitly in the definition of the default sub. The object is, after all, a hashref and the slots merely hash-keys. That is not how 'default' is used. Just have the sub return what you need in the slot and you will come to no grief.
The Lazy Moose
The lazy and default options options are linked. In fact, you cannot have a lazy attribute unless it has a default (or a builder, but we'll cover that later). If you try to make an attribute lazy without a default, class creation will fail with an exception.
What lazy means is that the slot is stuffed by the 'default' only upon request via accessor and not until then. This feature is so powerful and ingenious - certain applications may simply be impossible without it. Take for example a classical data structure in computer science - the binary tree. Without lazy loading, it leads to an implementation that consumes all of the computer's available memory. Now you wouldn't want that to happen to you, would you?
http://search.cpan.org/~drolsky/Moose-0.88/lib/Moose/Cookbook/Basics/Recipe3.pod
To Cook a Moose
(With apologies to a certain gun-toting Governor of Alaska.)
The 'BUILD' method is called after an object is created.
There are several ways to use a BUILD method. One of the most common is to check that the object state is valid. While we can validate individual attributes through the use of types, we can't validate the state of a whole object that way.
Why did the Moose weaken her reference?
Attribute 'weak_ref' assigned 1 ensures that the reference is weakened when it is set. So this reference will be ignored by Garbage Cleaning when handling the referred object. A weak reference will not prevent the referred object from being cleaned by garbage collector.
The Moose Modifies Her Methods
Method Modifiers are a Moose feature that allows hooking into code. One can alter class behavior by hooking into code before, after and even around. Basically, that means using the qualifiers 'before', 'after' and 'around' respectively.
Basically, a snippet of code encapsulated in a sub is executed before the modified method. (Or after, or around.)
Invoking the method that a method modifier hooks into in the definition of the method modifier leads to deep recursion.
That may sound obvious until one starts hooking into accessor/mutator methods to impose constraints, for example. This is a common occurrence when a slot is a container - such as an array (array-ref) or a hash (hash-ref). Then, usage of a method modifier to constrain the size of the container (for example) leads to disaster. Because to constrain the size of the container, you will need to access the slot .. get it?
The following DOs and DON'Ts for the methods 'before', 'after' should help one stay out of trouble -
DO
use Method Modification to add behavior to methods that Moose generates, such as accessor/mutator methods.
DON'T
however attempt to pre-process the arguments passed to the method thus modified. That will have no effect - changes to the argument list made in the method modifier are discarded when the said modifier exits. Speaking of which, return values are simply ignored.
DO
use method modification to execute logical checks that don't make sense as type constraints.
DON'T
however abuse this notion by attempting to rectify the input arguments. The correct action when checks fail is to raise an exception. In other words, die. Die! Or in the immortal words of the dying Creedy in "V for Vendetta", "Why won't you die?!" (To which, the masked character called "V" replies "Beneath this mask, there is no flesh, Mr. Creedy. Beneath this mask, is an Idea. And Ideas are bulletproof.")
Roundabout Moose
And just when you though method modification makes sense ..
.. Moose cruelly exposes your naivete!
The method modifier 'around', despite appearances, is fundamentally different from 'before' and 'after' - with 'around', you can modify the arguments being passed to the original method. You can even call the orginal method - as a matter of fact, you are required to. Unless you don't want to, that is. In which case, you need not call the original method at all.
Last, but not the least, you can modify the return value with 'around'. That is, if you want to. Wakarimasu ka?
As my martial arts instructor says, "Try it! You'll know." And that's enough for one day.
All code in this series may be downloaded from:
http://sites.google.com/site/sanjaybhatikar/codeunquote/designpatterns-1
http://sites.google.com/site/sanjaybhatikar/codeunquote/designpatterns-1
wakarimasen :o)
ReplyDelete