=head1 TYPES IN PERL?
-Moose provides its own type system for your class's attributes. You
-can also use these types to validate method parameters with the help
-of some MooseX modules.
+Moose provides its own type system for attributes. You can also use
+these types to validate method parameters with the help of a MooseX
+module.
Moose's type system is based on a combination of Perl 5's own
-I<implicit> types, and some Perl 6 concepts as well. But most
-importantly, you can easily create your own subtypes with custom
-constraints, making it easy to express any sort of validation.
+I<implicit> types and some Perl 6 concepts. You can easily create your
+own subtypes with custom constraints, making it easy to express any
+sort of validation.
-You can also name types and re-use them by name, making it easy to
+Types have names, and you can re-use them by name, making it easy to
share types throughout a large application.
Let us be clear that is not a "real" type system. Moose does not
-magically make Perl start associating types with variables. In many
-ways, this is really an advanced parameter checking system which
-allows you to associate a name with a constraintq.
+magically make Perl start associating types with variables. This is
+just an advanced parameter checking system which allows you to
+associate a name with a constraint.
That said, it's still pretty damn useful, and we think it's one of the
things that makes Moose both fun and powerful. Taking advantage of the
It's important to realize that types are not classes (or
packages). Types are just objects (L<Moose::Meta::TypeConstraint>
-objects, to be exact) with a name. Moose maintains a global type
-registry that lets it convert names like "Num" into the appropriuate
-object.
+objects, to be exact) with a name and a constraint. Moose maintains a
+global type registry that lets it convert names like "Num" into the
+appropriate object.
However, class names I<can be> type names. When you define a new class
using Moose, it defines an associated type name behind the scenes:
isa => 'ArrayRef[DateTime]',
);
-Moose will assume that "DateTime" is a class name and create a type
-accordingly.
+Moose will assume that "DateTime" is a class name in both of these
+instances.
=head1 SUBTYPES
A subtype is defined in terms of a parent type and a constraint. Any
constraints defined by the parent(s) will be checked first, and then
-the subtype's constraint is checked. A value must pass I<all> of these
-checks to be valid for the subtype.
+the the subtype's . A value must pass I<all> of these checks to be
+valid for the subtype.
-Generally, a subtype takes the parent's constraint and makes it more
+Typically, a subtype takes the parent's constraint and makes it more
specific.
A subtype can also define its own constraint failure message. This
type 'FourCharacters' => where { defined $_ && length $_ == 4 };
-In practice, this example is pretty much the same as doing the same
-thing as a subtype of C<Str>, except you have to check defined-ness
-yourself.
+In practice, this example is more or less the same as subtyping
+C<Str>, except you have to check defined-ness yourself.
It's hard to find a case where you wouldn't want to subtype a very
broad type like C<Defined>, C<Ref> or C<Object>.
-In practice, defining a new top-level type is conceptually the same as
-subtyping C<Item>.
+Defining a new top-level type is conceptually the same as subtyping
+C<Item>.
=head1 TYPE NAMES
Type names are global throughout the current Perl
-interpreter. Internally, Moose maps names to type objects via
-L<Moose::Meta::TypeConstraint::Registry|registry> singleton.
+interpreter. Internally, Moose maps names to type objects via a
+L<registry|Moose::Meta::TypeConstraint::Registry>.
If you have multiple apps or libraries all using Moose in the same
process, you could have problems with collisions. We recommend that
For example, instead of calling a type "PositiveInt", call it
"MyApp.Type.PositiveInt".
-Type names are just strings, and can contain any character you
-want. We recommend that you I<do not> use "::" as a separator in type
-names. This can be very confusing, because class names are I<also>
-valid type names! Using something else, like a period, makes it clear
-that "MyApp::User" is a class and "MyApp.Type.PositiveInt" is a Moose
-type defined by your application.
+Type names are just strings. We recommend that you I<do not> use "::"
+as a separator in type names. This can be very confusing, because
+class names are I<also> valid type names! Using something else, like a
+period, makes it clear that "MyApp::User" is a class and
+"MyApp.Type.PositiveInt" is a Moose type defined by your application.
The C<MooseX::Types> module lets you create bareword aliases to longer
-names (really, the barewords are functions).
+names and also automatically namespaces all the types you define.
=head1 COERCION
One of the most powerful features of Moose's type system is its
-coercions. A coercion is a mapping between two types.
+coercions. A coercion is a way to convert from one type to another.
subtype 'ArrayRefOfInts'
=> as 'ArrayRef[Int]';
);
If we try passing an array reference of hex numbers for the C<sizes>
-attribute, Moose will not do any coercion. The reason for this is that
-it gets very complicate very fast.
+attribute, Moose will not do any coercion.
-However, if you want to, you can define a set of subtypes to enable
-coercion between two parameterized types.
+However, you can define a set of subtypes to enable coercion between
+two parameterized types.
subtype 'ArrayRefOfHexNums'
=> as 'ArrayRef[HexNum]';
Now Moose will coerce the hex numbers to integers.
-However, Moose does not attempt to chain coercions, so we cannot pass
-a single hex number. If we want to make that possible as well, we need
-to define yet another coercion:
+However, Moose does not attempt to chain coercions, so it will not
+coerce a single hex number. To do that, we need to define a separate
+coercion:
coerce 'ArrayRefOfInts'
=> from 'HexNum'
=> via { [ hex $_ ] };
Yes, this can all get verbose, but coercion is tricky magic, and we
-think it's best to make it as explicit as possible.
+think it's best to make it explicit.
=head1 TYPE UNIONS
as well as an unblessed file handle. It is up to you to do the right
thing for each of them in your code.
-Whenever you consider using a type union, you should think about
-whether or not coercion might be a better answer.
+Whenever you use a type union, you should consider whether or not
+coercion might be a better answer.
For our example above, we might want to be more specific, and insist
that output be an object with a C<print> method:
Now we can define a coercion from C<FileHandle> to our wrapper class:
- coerce 'FHWrapper'
+ coerce 'CanPrint'
=> from 'FileHandle'
=> via { FHWrapper->new( handle => $_ ) };
coerce => 1,
);
-This pattern, using a coercion instead of a type union, can help
-simplify the use of the attribute, and should be considered whenever
-you have a type union.
+This pattern of using a coercion instead of a type union will help
+make your class internals simpler.
=head1 TYPE CREATION HELPERS
sub foo {
my $self = shift;
- my %params = validate(
+ my %params = validated_hash(
\@_,
bar => { isa => 'Str', default => 'Moose' },
);
=head1 LOAD ORDER ISSUES
-Because Moose types are defined at runtime, you can sometimes run into
-issues with load order. In particular, you may sometimes want to use a
-class's type constraint before it exists.
+Because Moose types are defined at runtime, you may run into load
+order problems. In particular, you may want to use a class's type
+constraint before that type has been defined.
-We recommend several things. First, define I<all> of your custom types
-in one module, C<MyApp::Types>. Second, load this module in all of
-your other modules.
+We have several recommendations for ameliorating this problem. First,
+define I<all> of your custom types in one module,
+C<MyApp::Types>. Second, load this module in all of your other
+modules.
If you are still having load order problems, you can make use of the
C<find_type_constraint> function exported by
L<Moose::Util::TypeConstraints>:
- my $type = find_type_constraint('MyApp::User') || class_type('MyApp::User');
+ class_type('MyApp::User')
+ unless find_type_constraint('MyApp::User') || ;
This sort of "find or create" logic is simple to write, and will let
you work around load order issues.