This is an old article. Some links may be broken. Some of the information may no longer be correct. Opinions expressed in this article may no longer be held.
Type::Tiny is probably best known as a way of having Moose-like type constraints in Moo, but it can be used for so much more. This is the third in a series of posts showing other things you can use Type::Tiny for. This article along with part 1, part 2, and part 3 can be found on my blog and in the Cool Uses for Perl section of PerlMonks.
Even if you read the documentation of Types::Standard pretty thoroughly, you’d probably miss that you can do things like this:
use Types::Standard qw(is_ArrayRef is_HashRef); if (is_ArrayRef($var)) { ...; } elsif (is_HashRef($var)) { ...; }
It is documented that Types::Standard exports functions called ArrayRef
and HashRef
, which are constant-like functions returning Moose/Moo-compatible type constraint objects, but where did these is_ArrayRef
and is_HashRef
functions come from?
Well, their existence is documented in Type::Library, the type library base class used by Types::Standard. Any type library built with it will offer is_*
variants of type constraints. These functions check their argument and return a boolean indicating whether it passes the type constraint.
The object-oriented way of writing these checks is like this:
use Types::Standard qw(ArrayRef HashRef); if (ArrayRef->check($var)) { ...; } elsif (HashRef->check($var)) { ...; }
Though the object-oriented way is a little slower because it will result in at least three sub calls (including a method call).
The is_*
functions should be pretty darn fast, especially if Type::Tiny::XS is installed. Ref::Util::XS is faster, and Params::Util is sometimes faster, but using Type::Library-based type libraries (such as Types::Standard, Types::Common::Numeric, Types::Common::String, Types::Path::Tiny, Types::XSD, etc) will give you a richer selection of types that you can check.
Assertions
A common use for type checking functions is to do something like:
is_ArrayRef($var) or die(...);
Type::Library-based type libraries offer a shortcut for this:
assert_ArrayRef($var);
The return value of the assert_*
functions (if they don’t die) is the parameter you passed to them, which makes it convenient to do things like:
use Types::Standard qw(assert_Object assert_ArrayRef); sub process_data { my $self = assert_Object( $_[0] ); my $data = assert_ArrayRef( $_[1] ); ...; }
The object-oriented equivalent of assert_Object($thing)
is Object->assert_return($thing)
. Due to overloading Object->($thing)
will also work.
Coercions
If a type constraint has coercions (like Path
from Types::Path::Tiny), there’s also a to_*
function:
use Types::Path::Tiny qw( to_Path ); my $path = to_Path($thing);
Note that if a coercion fails, there is no exception thrown, and the original value is passed through unaltered. If you want to make sure coercion succeeded:
use Types::Path::Tiny qw( assert_Path to_Path ); my $path = assert_Path( to_Path($thing) );
The object-oriented equivalent of to_Path($thing)
is Path->coerce($thing)
. The object-oriented equivalent of assert_Path(to_Path($thing))
is Path->assert_coerce($thing)
.
Parameterized Types
It would be pretty cool if you could do:
if (is_ArrayRef[Int]($var)) { ...; }
But that wouldn’t be syntactically valid Perl.
You can do this though:
use Types::Standard qw(ArrayRef Int); BEGIN { my $type = ArrayRef->of(Int); *is_ArrayRef_of_Int = $type->compiled_check; *assert_ArrayRef_of_Int = \&{ $type }; *to_ArrayRef_of_Int = sub { $type->coerce(@_) }; } if (is_ArrayRef_of_Int($var)) { ...; }
Exporting Tricks
To export just Object
:
use Types::Standard qw(Object);
To export just is_Object
:
use Types::Standard qw(is_Object);
To export Object
and is_Object
:
use Types::Standard qw(Object is_Object);
To export Object
and all related functions (is_Object
, assert_Object
, and to_Object
):
use Types::Standard qw(+Object);
To export Object
, ArrayRef
, and all the other types:
use Types::Standard qw(:types);
To export Object
, ArrayRef
, all the other types, and the related is_*
functions:
use Types::Standard qw(:types :is);
To export Object
, ArrayRef
, all the other types, and the related is_*
, assert_*
, and to_*
functions:
use Types::Standard qw(:types :is :assert :to);