-=pod
+package Moose::Manual::Types;
+
+# ABSTRACT: Moose's type system
-=head1 NAME
+__END__
-Moose::Manual::Types - Moose's type system
+=pod
=head1 TYPES IN PERL?
module.
Moose's type system is based on a combination of Perl 5's own
-I<implicit> types and some Perl 6 concepts. You can easily create your
+I<implicit> types and some Perl 6 concepts. You can create your
own subtypes with custom constraints, making it easy to express any
sort of validation.
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. This is
-just an advanced parameter checking system which allows you to
-associate a name with a constraint.
+However, this is not a "real" type system. Moose does not 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
Defined
Value
Str
- Num
- Int
- ClassName
- RoleName
+ Num
+ Int
+ ClassName
+ RoleName
Ref
ScalarRef[`a]
ArrayRef[`a]
CodeRef
RegexpRef
GlobRef
- FileHandle
+ FileHandle
Object
In practice, the only difference between C<Any> and C<Item> is
=over 4
-=item C<Bool> accepts C<1> for true, and any value that perl treats as false for false.
+=item
+
+C<Bool> accepts C<1> for true, and undef, 0, or the empty string as false.
+
+=item
+
+C<Maybe[`a]> accepts either C<`a> or C<undef>.
+
+=item
-=item C<Maybe[`a]> accepts either C<`a> or C<undef>.
+C<Num> accepts anything that perl thinks looks like a number (see L<Scalar::Util/looks_like_number>).
-=item C<Num> accepts anything that perl thinks looks like a number (see L<Scalar::Util/looks_like_number>).
+=item
-=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.
+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 already be loaded when the constraint is checked.
-=item C<FileHandle> accepts either an object of type L<IO::Handle> or a builtin perl filehandle (see L<Scalar::Util/openhandle>).
+=item
-=item C<Object> accepts any blessed reference.
+C<FileHandle> accepts either an L<IO::Handle> object or a builtin perl filehandle (see L<Scalar::Util/openhandle>).
+
+=item
+
+C<Object> accepts any blessed reference.
=back
lets you do things like have an error "The value you provided (20),
was not a valid rating, which must be a number from 1-10." This is
much friendlier than the default error, which just says that the value
-failed a validation check for the type.
+failed a validation check for the type. The default error can, however,
+be made more friendly by installing L<Devel::PartialDump> (version 0.14 or
+higher), which Moose will use if possible to display the invalid value.
Here's a simple (and useful) subtype example:
- subtype 'PositiveInt'
- => as 'Int'
- => where { $_ > 0 }
- => message { "The number you provided, $_, was not a positive number" }
+ subtype 'PositiveInt',
+ as 'Int',
+ where { $_ > 0 },
+ message { "The number you provided, $_, was not a positive number" };
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)
-
-You can also create new top-level types:
-
- type 'FourCharacters' => where { defined $_ && length $_ == 4 };
-
-In practice, this example is more or less the same as subtyping
-C<Str>, except you have to check definedness 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>.
-
-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
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.
+However, before you do this, you should 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);
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:
+everywhere. It also allows you to easily create parameterized types:
has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]);
=head1 COERCION
-One of the most powerful features of Moose's type system is its
-coercions. A coercion is a way to convert from one type to another.
+A coercion lets you tell Moose to automatically convert one type to another.
- subtype 'ArrayRefOfInts'
- => as 'ArrayRef[Int]';
+ subtype 'ArrayRefOfInts',
+ as 'ArrayRef[Int]';
- coerce 'ArrayRefOfInts'
- => from 'Int'
- => via { [ $_ ] };
+ coerce 'ArrayRefOfInts',
+ from 'Int',
+ via { [ $_ ] };
-You'll note that we had to create a subtype rather than coercing
-C<ArrayRef[Int]> directly. This is just a quirk of how Moose
-works.
+You'll note that we created a subtype rather than coercing C<ArrayRef[Int]>
+directly. It's a bad idea to add coercions to the raw built in
+types.
-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 option to a true value:
+Coercions are global, just like type names, so a coercion applied to a built
+in type is seen by all modules using Moose types. 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 option to a true value:
package Foo;
Deep coercion is the coercion of type parameters for parameterized
types. Let's take these types as an example:
- subtype 'HexNum'
- => as 'Str'
- => where { /[a-f0-9]/i };
+ subtype 'HexNum',
+ as 'Str',
+ where { /[a-f0-9]/i };
- coerce 'Int'
- => from 'HexNum'
- => via { hex $_ };
+ coerce 'Int',
+ from 'HexNum',
+ via { hex $_ };
has 'sizes' => (
is => 'ro',
However, you can define a set of subtypes to enable coercion between
two parameterized types.
- subtype 'ArrayRefOfHexNums'
- => as 'ArrayRef[HexNum]';
+ subtype 'ArrayRefOfHexNums',
+ as 'ArrayRef[HexNum]';
- subtype 'ArrayRefOfInts'
- => as 'ArrayRef[Int]';
+ subtype 'ArrayRefOfInts',
+ as 'ArrayRef[Int]';
- coerce 'ArrayRefOfInts'
- => from 'ArrayRefOfHexNums'
- => via { [ map { hex } @{$_} ] };
+ coerce 'ArrayRefOfInts',
+ from 'ArrayRefOfHexNums',
+ via { [ map { hex } @{$_} ] };
Foo->new( sizes => [ 'a1', 'ff', '22' ] );
Now Moose will coerce the hex numbers to integers.
-However, Moose does not attempt to chain coercions, so it will not
+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 $_ ] };
+ 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 explicit.
For our example above, we might want to be more specific, and insist
that output be an object with a C<print> method:
- subtype 'CanPrint'
- => as 'Object'
- => where { $_->can('print') };
+ duck_type 'CanPrint', [qw(print)];
We can coerce file handles to an object that satisfies this condition
with a simple wrapper class:
my $self = shift;
my $fh = $self->handle();
- print $fh @_;
+ print {$fh} @_;
}
Now we can define a coercion from C<FileHandle> to our wrapper class:
The L<Moose::Util::TypeConstraints> module exports a number of helper
functions for creating specific kinds of types. These include
-C<class_type>, C<role_type>, and C<maybe_type>. See the docs for
-details.
+C<class_type>, C<role_type>, C<maybe_type>, and C<duck_type>. See the
+docs for details.
One helper worth noting is C<enum>, which allows you to create a
subtype of C<Str> that only allows the specified values:
- enum 'RGB' => qw( red green blue );
+ enum 'RGB', [qw( red green blue )];
This creates a type named C<RGB>.
type, or as the value for an attribute's C<isa> option:
has 'size' => (
- is => 'ro',
- 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
L<MooseX::Method::Signatures>, which gives you a full-blown C<method>
keyword.
- method morning (Str $name) {
+ method morning ( Str $name ) {
$self->say("Good morning ${name}!");
}
order problems. In particular, you may want to use a class's type
constraint before that type has been defined.
-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>:
-
- 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>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2009 by Infinity Interactive, Inc.
-
-L<http://www.iinteractive.com>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
+In order to ameliorate this problem, we recommend defining I<all> of your
+custom types in one module, C<MyApp::Types>, and then loading this module in
+all of your other modules.
=cut