=head1 NAME
-Moose::Manual::Types - Moose's Type System
+Moose::Manual::Types - Moose's type system
=head1 TYPES IN PERL?
Undef
Defined
Value
- Num
- Int
Str
+ Num
+ Int
ClassName
+ RoleName
Ref
- ScalarRef
+ ScalarRef[`a]
ArrayRef[`a]
HashRef[`a]
CodeRef
GlobRef
FileHandle
Object
- Role
In practice, the only difference between C<Any> and C<Item> is
conceptual. C<Item> is used as the top-level type in the hierarchy.
-The rest of these types correspond to existing Perl concepts. For
-example, a C<Num> is anything that Perl thinks looks like a number. An
-C<Object> is a blessed reference, etc.
+The rest of these types correspond to existing Perl concepts.
+In particular:
+
+=over 4
+
+=item C<Bool> accepts C<1> for true, and any value that perl treats as false for false.
+
+=item C<Maybe[`a]> accepts either C<`a> or C<undef>.
+
+=item C<Num> accepts anything that perl thinks looks like a number (see L<Scalar::Util/looks_like_number>).
+
+=item C<ClassName> and C<RoleName> accept strings that are either the name of a class or the name of a role. The class/role must be loaded beforehand for this to succeed.
+
+=item C<FileHandle> accepts either an object of type L<IO::Handle> or a builtin perl filehandle (see L<Scalar::Util/openhandle>).
+
+=item C<Object> accepts any blessed reference.
+
+=back
The types followed by "[`a]" can be parameterized. So instead of just
plain C<ArrayRef> we can say that we want C<ArrayRef[Int]> instead. We
The C<Maybe[`a]> type deserves a special mention. Used by itself, it
doesn't really mean anything (and is equivalent to C<Item>). When it
is parameterized, it means that the value is either C<undef> or the
-parameterized type. So C<Maybe[Int]> means an integer or C<undef>
+parameterized type. So C<Maybe[Int]> means an integer or C<undef>.
For more details on the type hierarchy, see
L<Moose::Util::TypeConstraints>.
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 and a constraint. Moose maintains a
-global type registry that lets it convert names like "Num" into the
+global type registry that lets it convert names like C<Num> into the
appropriate object.
However, class names I<can be> type names. When you define a new class
Now you can use C<'MyApp::User'> as a type name:
has creator => (
- is => 'rw',
+ is => 'ro',
isa => 'MyApp::User',
);
attribute is a class. So this works:
has 'birth_date' => (
- is => 'rw',
+ is => 'ro',
isa => 'DateTime',
);
isa => 'ArrayRef[DateTime]',
);
-Moose will assume that "DateTime" is a class name in both of these
+Moose will assume that C<DateTime> is a class name in both of these
instances.
=head1 SUBTYPES
-Moose uses subtypes in its built-in hierarchy. C<Int> is a child of
-C<Num> for example.
+Moose uses subtypes in its built-in hierarchy. For example, C<Int> is
+a child of C<Num>.
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 the subtype's . A value must pass I<all> of these checks to be
-valid for the subtype.
+constraints defined by the parent(s) will be checked first, followed by
+constraints defined by the subtype. A value must pass I<all> of these
+checks to be valid for the subtype.
Typically, a subtype takes the parent's constraint and makes it more
specific.
Note that the sugar functions for working with types are all exported
by L<Moose::Util::TypeConstraints>.
-=head2 Creating a New Type (That Isn't a Subtype)
+=head2 Creating a new type (that isn't a subtype)
You can also create new top-level types:
these sorts of collisions.
For example, instead of calling a type "PositiveInt", call it
-"MyApp.Type.PositiveInt".
+"MyApp::Type::PositiveInt" or "MyApp::Types::PositiveInt". We
+recommend that you centralize all of these definitions in a single
+package, C<MyApp::Types>, which can be loaded by other classes in your
+application.
+
+Once you're doing this, you should almost certainly look at the
+L<MooseX::Types> module. This module makes it easy to create a "type library"
+module, which can export your types as perl constants.
+
+ has 'counter' => (is => 'rw', isa => PositiveInt);
-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.
+This lets you use a short name rather than needing to fully qualify the name
+everywhere. It also allows you to write easily create parameterized types:
-The C<MooseX::Types> module lets you create bareword aliases to longer
-names and also automatically namespaces all the types you define.
+ has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]);
+
+This module will check your names at compile time, and is generally more
+robust than the string type parsing for complex cases.
=head1 COERCION
Coercions, like type names, are global. This is I<another> reason why
it is good to namespace your types. Moose will I<never> try to coerce
a value unless you explicitly ask for it. This is done by setting the
-C<coerce> attribute parameter to a true value:
+C<coerce> attribute option to a true value:
package Foo;
has 'sizes' => (
- is => 'rw',
+ is => 'ro',
isa => 'ArrayRefOfInts',
coerce => 1,
);
This code example will do the right thing, and the newly created
object will have C<[ 42 ]> as its C<sizes> attribute.
-=head2 Deep Coercion
+=head2 Deep coercion
Deep coercion is the coercion of type parameters for parameterized
types. Let's take these types as an example:
=> via { hex $_ };
has 'sizes' => (
- is => 'rw',
+ is => 'ro',
isa => 'ArrayRef[Int]',
coerce => 1,
);
use Moose;
has 'handle' => (
- is => 'ro',
+ is => 'rw',
isa => 'FileHandle',
);
enum 'RGB' => qw( red green blue );
-This creates a type named C<RGB>
+This creates a type named C<RGB>.
=head1 ANONYMOUS TYPES
All of the type creation functions return a type object. This type
object can be used wherever you would use a type name, as a parent
-type, or as the value for an attribute's C<isa> parameter:
+type, or as the value for an attribute's C<isa> option:
has 'size' => (
- is => 'rw',
- isa => subtype 'Int' => where { $_ > 0 },
+ is => 'ro',
+ isa => subtype('Int' => where { $_ > 0 }),
);
This is handy when you want to create a one-off type and don't want to
parameters. However, there are several MooseX extensions on CPAN which
let you do this.
-The simplest and least sugary is C<MooseX::Params::Validate>. This
+The simplest and least sugary is L<MooseX::Params::Validate>. This
lets you validate a set of named parameters using Moose types:
use Moose;
...
}
-C<MooseX::Params::Validate> also supports coercions.
+L<MooseX::Params::Validate> also supports coercions.
There are several more powerful extensions that support method
parameter validation using Moose types, including
-C<MooseX::Method::Signatures>, which gives you a full-blown C<method>
+L<MooseX::Method::Signatures>, which gives you a full-blown C<method>
keyword.
method morning (Str $name) {
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>:
-
- 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.
-
=head1 AUTHOR
Dave Rolsky E<lt>autarch@urth.orgE<gt>