-=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
Undef
Defined
Value
- Num
- Int
Str
- ClassName
- RoleName
+ Num
+ Int
+ ClassName
+ RoleName
Ref
- ScalarRef
+ ScalarRef[`a]
ArrayRef[`a]
HashRef[`a]
CodeRef
RegexpRef
GlobRef
- FileHandle
+ FileHandle
Object
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 undef, 0, or the empty string as 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 already be loaded when the constraint is checked.
+
+=item
+
+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
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
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> extension which allows easy declaration of type libraries
-and can export your types as perl constants so that you can refer to them
-as just
+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);
-rather than needing to fully qualify them everywhere. It also allows
+This lets you use a short name rather than needing to fully qualify the name
+everywhere. It also allows you to easily create parameterized types:
has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]);
-and similarly for the union and other syntax discussed below, which
-will compile time check your use of names and is generally more robust
-than the string type parsing for complex cases.
+This module will check your names at compile time, and is generally more
+robust than the string type parsing for complex cases.
=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 created a subtype rather than coercing C<ArrayRef[Int]>
+directly. It's a bad idea to add coercions to the raw built in
+types.
-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.
+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.
-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:
+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