Moose::Cookbook::Style - The latest in trendy Moose cuisine
Please annotate all bad examples with comments so that they won't be copied by accident
Good Moose style, as defined by this document, helps ensure your code has the following desirable properties:
Your code will be more reusable and easier to extend.
The code will be easier to understand because it follows an accepted set of conventions and idioms.
This will help others maintaining your code, and also help you to get support on IRC for instance.
By using the most appropriate features, the generated code will be safer and more efficient.
Code that operates on the metaclass will benefit from clean meta definitions.
If you are manually converting argument types with around 'new' there is no meta data explaining your intention. If on the other hand you use coercions, there is introspectable meta data that makes this clear.
around 'new'
This means that e.g. MooseX extensions that work by introspecting your class will be able to do the right thing more often, because they don't need to guess.
new
It is generally considered bad style to override "new" in Moose::Object for a number of reasons.
The first reason is consistency. Subclasses of your class and code instantiating your class would be simpler if your constructor works closer to the default.
The second reason is performance. By calling make_immutable on your metaclass:
make_immutable
__PACKAGE__->meta->make_immutable;
And opting out of any class definition changes from that point on, you allow Moose to create more efficient versions of certain generic methods. Moose will generate a tight, optimal new for you, based on the minimal set of features you use.
Moose provides many features that allow you to do common object construction tasks at the right level of abstraction.
When attributes have the ability to provide the necessary functionality, use that. If that isn't sufficient, Moose::Object has numerous features you can use at construction time.
BUILD
Instead of changing new, do initialization in BUILD.
The construction parameters are passed in, so you don't need to replicate BUILDARGS, and since BUILD is called for each superclass that defines it, you will never forget to invoke your initializers if you extend them.
BUILDARGS
default
builder
lazy_build
To initialize attributes there is a plethora of methods preferable to assigning the value at initialization time.
If you want to translate parameter data, use coercions.
If you want to ensure a parameter can't be overridden by the constructor, set the init_arg to undef instead of overwriting it in BUILD.
init_arg
undef
@_
If you need to change the way @_ is processed, for example for Class->new( $single_param ), use BUILDARGS instead of wrapping new. This ensures the behavior is subclassible, it keeps this logic independent of the other aspects of construction, and can be made efficient using make_immutable.
Class->new( $single_param )
MooseX::Types provides a convenient method to do this.
If you define
# Bad style: subtype Person => ( as 'Object', where { $_->can("name") }, );
Then the global name Person is registered, and this could conflict with other bad usage of the sort.
Person
Instead, prefix type name with your project namespace, or class name:
subtype 'My::Foo::Person' => ( as 'Object', where { $_->can("name") }, );
Or with MooseX::Types:
use MooseX::Types::Moose qw(Object); use MooseX::Types ( -declare => [qw(Person)], ); subtype Person() => ( # note parenthesis, "Person" is a function, not a string as Object, # MooseX::Types::Moose exported it where { $_->can("name") }, );
Likewise use fully qualified subtypes of other types for defining coercions, so that they won't affect unrelated code, causing action at a distance.
This is important because the type registry is global, kind of like the symbol table.
This means that code like:
# Bad style: coerce ArrayRef => ( from Str => via { [ split /,/ ] }, );
Will add a coercion to all attributes like:
has foo => ( isa => "ArrayRef", coerce => 1, );
when the actual coercion applies only to your specific cases.
Use namespace::clean or no Moose to remove the sugar exports.
namespace::clean
no Moose
This will make sure the sugar isn't accidentally called as methods on your objects.
For instance:
$obj->can("has");
will return true, even though has is not a method.
has
By substitutes I mean hacks instead of "proper" solutions.
When you have a tricky requirement, refrain from abusing Moose or MooseX:: or whatever it is you are using.
Instead, drop by IRC and discuss it. Most of the time a crazy idea can either be simplified, or it will spawn a clean, reliable feature to whatever package you are using.
This will improve your code and also share the benefit with others.
Yuval (nothingmuch) Kogman
Copyright 2006-2008 by Infinity Interactive, Inc.
http://www.iinteractive.com
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Moose, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Moose
CPAN shell
perl -MCPAN -e shell install Moose
For more information on module installation, please visit the detailed CPAN module installation guide.