Moose

Moose Sugar

Moose is really nothing more than syntactic "sugar" that automatically takes care of the boiler-plate tedium and low-level details of implementing objects automatically. This is possible because of Perl's powerful introspection capabilities—Moose dynamically manipulates the class definition at compile time just as if it had been written that way.

The previous class could be implemented like this with Moose:


package MyApp::Rifle;
use Moose;

has 'rounds' => ( is => 'rw', isa => 'Int', default => 0 );

sub fire {
        my $self = shift;
        die "out of ammo!" unless ($self->rounds > 0);
        print "bang!\n";
        $self->rounds( $self->rounds - 1 );
}

1;

Not only is this code much shorter, cleaner and easier to read, but it is doing all the things the non-Moose class was doing and more. First, Moose is automatically creating the "new" constructor method behind the scenes. It is also automatically setting up "rounds" as an attribute (aka object variable), which Moose understands as a distinct concept.

Pure Perl has no such understanding; if you want "attributes", you have to implement them yourself by writing accessor methods by hand and deciding how they should work (the non-Moose version above illustrates only one of many possible approaches).

Moose, on the other hand, provides a refined, fully integrated object attribute paradigm. It sets up the accessor methods, handles the data storage and retrieval, and automatically configures the constructor to initialize attributes optionally with supplied parameters—and that is just scratching the surface!

One of the problems with the non-Moose version of our class is that there is no validation for "rounds". For example, nothing stops us from doing this:


my $rifle = MyApp::Rifle->new( rounds => 'foo' );

This is one of the areas where Moose really shines; it provides a complete Type system that is very straightforward to use. In the Moose version, the option isa => 'Int' sets up the rounds attribute with a type constraint that automatically will throw an exception (with a meaningful message) if you try to set the value to anything that is not a valid integer. This would stop you from setting rounds to 'foo' because it's not an integer, it's a string.

This illustrates an important point about Moose's design and approach. Its syntax is declarative rather than imperative. This means you just need to specify what you want it to do instead of how it needs to do it. This is in sharp contrast to the traditional Perl 5 OO style, where that is exactly what you would have to do—add additional lines of code in the accessor method to test the value for validity and handle the result.

The syntax isa => 'Int' doesn't provide any insight on how Moose will go about checking and enforcing the type constraint. And that's the whole point—you don't care. But, you can rest assured it will do it in a far more thorough and robust manner than anything you'd want to waste time on doing yourself.

More about Attributes

You declare attributes in Moose with the "has" function. This consists of a unique attribute name, followed by a list of named options (key/values). Although it looks and behaves like a built-in language keyword, it is really just a function call. Its documented syntax is just idiomatic for the purpose of code readability (it's a fancy way to pass an argument list).

Moose provides all sorts of options that define the behavior of a given attribute, including setup of accessors, data types, initialization and event hooks. The simplest attribute is just an object variable that is set up as either read-write (rw) or read-only (ro) with the "is" option:


has 'first_name' => ( is => 'rw' ); 

The is option tells Moose to set up the accessor method, which is what you use to get and set the attribute's value. You set the value of an attribute by passing a single argument to the accessor (such as $obj->first_name('Fred')), and you get the current value by calling the accessor with no arguments ($obj->first_name). Setting the value is only allowed if the attribute "is" => "rw". If it's "ro", and you try to set its value through the accessor an exception will be thrown.

This is the core of the attribute paradigm, but lots of other options provide useful features. Here are a few of the noteworthy ones:

  • is: ro or rw, creates either a read-only or read-write accessor method.

  • isa: string representing an optional type constraint.

  • default: the default value of the attribute.

  • builder: alternative to default—name of a method that will generate the default.

  • lazy: if true, the attribute is not initialized until it's used.

  • required: if true, attribute value must be provided to constructor or have default/builder.

The builder option lets you specify a method to use to populate the attribute's default value. A builder is a normal method defined within the class, and its return value is used to set the attribute's initial value. If the builder needs to access other attributes within the object, the attribute must be lazy (to prevent it from potentially being populated before the other attributes it depends on).

Because this is such a common scenario, for convenience, Moose provides the "lazy_build" attribute option that automatically sets the lazy option and sets the builder to _build_name (such as _build_first_name for an attribute named first_name). For example:


has 'first_name' => ( is => 'ro', lazy_build => 1 );
sub _build_first_name {
        my $self = shift;
        return $self->some_lookup('some data');
}

Attributes Containing Objects

So far, I've talked only about attributes containing simple scalars. Attributes can contain other types of values as well, including references and other objects. For example, you could add a DateTime attribute to your MyApp::Rifle class to keep track of the last time "fire" was called:


package MyApp::Rifle;
use Moose;
use DateTime;

has 'rounds' => ( is => 'rw', isa => 'Int', default => 0 );
has 'fired_dt' => ( is => 'rw', isa => 'DateTime' );

sub fire {
        my $self = shift;
        die "out of ammo!" unless ($self->rounds > 0);
	
        my $dt = DateTime->now( time_zone => 'local' );
        $self->fired_dt($dt);
	
        print "bang!\n";
        print "fired at " . $self->fired_dt->datetime . "\n";
	
        $self->rounds( $self->rounds - 1 );
}

1;

This is fairly straightforward. I'm creating a new DateTime object and storing it in my fired_dt attribute. Then, I can call methods on this object, such as the datetime method, which returns a friendly string representing the date and time.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

I guess the basic question

ionutpop's picture

I guess the basic question this raises is whether ease of development for you beats usefulness to others. If that ticket is representative, it suggests that actual users feel that converting to Moose is transferring an unwelcome cost them, and so you might end up with modules that are easy to maintain, but unused. That more people might use Moose in the future is speculation, but this complaint is from an actual user.

Perhaps it would be better to wait for requests to Moose-ify existing modules, and if they don’t come, don’t bother. If converting to Moose is that simple, surely someone will send some patches to you, or fork the module, if they want a Moose version.

Instead, just consider Moose for new code, where there is no opportunity to encourage take-up by people looking for lightweight code, only to find it switched to what they think is heaviness after the fact.

Ianis from bet365.com

nice of artical Save the

juliajin's picture

nice of artical Save the aloft chic analogue into a book called MyApp/Rifle.pm aural one of your Perl's cover directories, and again you can use it in a Perl affairs like this. jogos de motos

Moose is awesome!

Chankey Pathak's picture

Thanks for this tutorial on Moose. Moose is simply awesome!

Intresting I have ner use

pilot school's picture

Intresting I have ner use Mose, but after reading this i might give it a try

----- http://ai.vc/zd

bdso8f9sa's picture

----- http://ai.vc/zd -----

Hi,Dear Ladies and Gentlemen,
1. sport shoes : Jordan ,Nike, adidas, Puma, Gucci, LV, UGG , etc. including women shoes and kids shoes.
2. T-Shirts : BBC T-Shirts, Bape T-Shirts, Armani T-Shirts, Polo T-Shirts,etc.
3. Hoodies : Bape hoody, hoody, AFF hoody, GGG hoody, ED hoody ,etc.
4. Jeans : Levis jeans , Gucci jeans, jeans, Bape jeans , DG jeans ,etc.
----- http://ai.vc/zd -----
----- http://ai.vc/zd -----

Service is our Lift.

enjoy yourself.

thank you!!

::∴★∵**☆.∴★∵**☆.∴★∵**☆.
█████.::∴★∵**☆.∴★∵**☆.
█田█田█::∴★∵**☆.∴★∵**☆.
█田█田█.∴★∵**☆.∴★∵**☆.
█田█田█∴★∵**☆.∴★∵**☆.
█田█田█.★∵**☆.∴★∵**☆.
█████.*******************
◢██□██◣.~~~~~*^_^*

thanx

Benzeb's picture

thanx for this article.
I've been laying with perl for some years now, but never gave a try to Moose.
Now that i have a clearer view to what Moose it, i have to try it

ps : Perl IS wonderful !! Can't understand why people enjoy php much more than Perl

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState