1Type::Tiny::Manual::LibUrsaerrieCso(n3t)ributed Perl DocTuympeen:t:aTtiinoyn::Manual::Libraries(3)
2
3
4

NAME

6       Type::Tiny::Manual::Libraries - defining your own type libraries
7

MANUAL

9   Defining a Type
10       A type is an object and you can create a new one using the constructor:
11
12         use Type::Tiny;
13
14         my $type = Type::Tiny->new(%args);
15
16       A full list of the available arguments can be found in the Type::Tiny
17       documentation, but the most important ones to begin with are:
18
19       "name"
20           The name of your new type. Type::Tiny uses a convention of
21           UpperCamelCase names for type constraints. The type name may also
22           begin with one or two leading underscores to indicate a type
23           intended for internal use only.  Types using non-ASCII characters
24           may cause problems on older versions of Perl (pre-5.8).
25
26           Although this is optional and types may be anonymous, a name is
27           required for a type constraint to added to a type library.
28
29       "constraint"
30           A code reference checking $_ and returning a boolean.
31           Alternatively, a string of Perl code may be provided.
32
33           If you've been paying attention, you can probably guess that the
34           string of Perl code may result in more efficient type checks.
35
36       "parent"
37           An existing type constraint to inherit from. A value will need to
38           pass the parent constraint before its own constraint would be
39           called.
40
41             my $Even = Type::Tiny->new(
42               name       => 'EvenNumber',
43               parent     => Types::Standard::Int,
44               constraint => sub {
45                 # in this sub we don't need to check that $_ is an Int
46                 # because the parent will take care of that!
47
48                 $_ % 2 == 0
49               },
50             );
51
52           Although the "parent" is optional, it makes sense whenever possible
53           to inherit from an existing type constraint to benefit from any
54           optimizations or XS implementations they may provide.
55
56   Defining a Library
57       A library is a Perl module that exports type constraints as subs.
58       Types::Standard, Types::Common::Numeric, and Types::Common::String are
59       type libraries that are bundled with Type::Tiny.
60
61       To create a type library, create a package that inherits from
62       Type::Library.
63
64         package MyTypes {
65           use Type::Library -base;
66
67           ...; # your type definitions go here
68         }
69
70       The "-base" flag is just a shortcut for:
71
72         package MyTypes {
73           use Type::Library;
74           our @ISA = 'Type::Library';
75         }
76
77       You can add types like this:
78
79         package MyTypes {
80           use Type::Library -base;
81
82           my $Even = Type::Tiny->new(
83             name       => 'EvenNumber',
84             parent     => Types::Standard::Int,
85             constraint => sub {
86               # in this sub we don't need to check that $_ is an Int
87               # because the parent will take care of that!
88
89               $_ % 2 == 0
90             },
91           );
92
93           __PACKAGE__->add_type($Even);
94         }
95
96       There is a shortcut for adding types if they're going to be blessed
97       Type::Tiny objects and not, for example, a subclass of Type::Tiny.  You
98       can just pass %args directly to "add_type".
99
100         package MyTypes {
101           use Type::Library -base;
102
103           __PACKAGE__->add_type(
104             name       => 'EvenNumber',
105             parent     => Types::Standard::Int,
106             constraint => sub {
107               # in this sub we don't need to check that $_ is an Int
108               # because the parent will take care of that!
109
110               $_ % 2 == 0
111             },
112           );
113         }
114
115       The "add_type" method returns the type it just added, so it can be
116       stored in a variable.
117
118         my $Even = __PACKAGE__->add_type(...);
119
120       This can be useful if you wish to use $Even as the parent type to some
121       other type you're going to define later.
122
123       Here's a bigger worked example:
124
125         package Example::Types {
126           use Type::Library -base;
127           use Types::Standard -types;
128           use DateTime;
129
130           # Type::Tiny::Class is a subclass of Type::Tiny for creating
131           # InstanceOf-like types. It's kind of better though because
132           # it does cool stuff like pass through $type->new(%args) to
133           # the class's constructor.
134           #
135           my $dt = __PACKAGE__->add_type(
136             Type::Tiny::Class->new(
137               name    => 'Datetime',
138               class   => 'DateTime',
139             )
140           );
141
142           my $dth = __PACKAGE__->add_type(
143             name    => 'DatetimeHash',
144             parent  => Dict[
145               year       => Int,
146               month      => Optional[ Int ],
147               day        => Optional[ Int ],
148               hour       => Optional[ Int ],
149               minute     => Optional[ Int ],
150               second     => Optional[ Int ],
151               nanosecond => Optional[ Int ],
152               time_zone  => Optional[ Str ],
153             ],
154           );
155
156           my $eph = __PACKAGE__->add_type(
157             name    => 'EpochHash',
158             parent  => Dict[ epoch => Int ],
159           );
160
161           # Can't just use "plus_coercions" method because that creates
162           # a new anonymous child type to add the coercions to. We want
163           # to add them to the type which exists in this library.
164           #
165           $dt->coercion->add_type_coercions(
166             Int,    q{ DateTime->from_epoch(epoch => $_) },
167             Undef,  q{ DateTime->now() },
168             $dth,   q{ DateTime->new(%$_) },
169             $eph,   q{ DateTime->from_epoch(%$_) },
170           );
171
172           __PACKAGE__->make_immutable;
173         }
174
175       "make_immutable" freezes to coercions of all the types in the package,
176       so no outside code can tamper with the coercions, and allows Type::Tiny
177       to make optimizations to the coercions, knowing they won't later be
178       altered. You should always do this at the end.
179
180       The library will export types Datetime, DatetimeHash, and EpochHash.
181       The Datetime type will have coercions from Int, Undef, DatetimeHash,
182       and EpochHash.
183
184   Extending Libraries
185       Type::Utils provides a helpful function "extends".
186
187         package My::Types {
188           use Type::Library -base;
189           use Type::Utils qw( extends );
190
191           BEGIN { extends("Types::Standard") };
192
193           # define your own types here
194         }
195
196       The "extends" function (which you should usually use in a "BEGIN { }"
197       block not only loads another type library, but it also adds all the
198       types from it to your library.
199
200       This means code using the above My::Types doesn't need to do:
201
202         use Types::Standard qw( Str );
203         use My::Types qw( Something );
204
205       It can just do:
206
207         use My::Types qw( Str Something );
208
209       Because all the types from Types::Standard have been copied across into
210       My::Types and are also available there.
211
212       "extends" can be passed a list of libraries; you can inherit from
213       multiple existing libraries. It can also recognize and import types
214       from MooseX::Types, MouseX::Types, and Specio::Exporter libraries.
215
216       Since Type::Library 1.012, there has been a shortcut for "extends".
217
218         package My::Types {
219           use Type::Library -extends => [ 'Types::Standard' ];
220
221           # define your own types here
222         }
223
224       The "-extends" flag takes an arrayref of type libraries to extend.  It
225       automatically implies "-base" so you don't need to use both.
226
227   Custom Error Messages
228       A type constraint can have custom error messages. It's pretty simple:
229
230         Type::Tiny->new(
231           name       => 'EvenNumber',
232           parent     => Types::Standard::Int,
233           constraint => sub {
234             # in this sub we don't need to check that $_ is an Int
235             # because the parent will take care of that!
236
237             $_ % 2 == 0
238           },
239           message   => sub {
240             sprintf '%s is not an even number', Type::Tiny::_dd($_);
241           },
242         );
243
244       The message coderef just takes a value in $_ and returns a string.  It
245       may use "Type::Tiny::_dd()" as a way of pretty-printing a value.
246       (Don't be put off by the underscore in the function name. "_dd()" is an
247       officially supported part of Type::Tiny's API now.)
248
249       You don't have to use "_dd()". You can generate any error string you
250       like. But "_dd()" will help you make undef and the empty string look
251       different, and will pretty-print references, and so on.
252
253       There's no need to supply an error message coderef unless you really
254       want custom error messages. The default sub should be reasonable.
255
256   Inlining
257       In Perl, sub calls are relatively expensive in terms of memory and CPU
258       use.  The PositiveInt type inherits from Int which inherits from Num
259       which inherits from Str which inherits from Defined which inherits from
260       Item which inherits from Any.
261
262       So you might think that to check of $value is a PositiveInt, it needs
263       to be checked all the way up the inheritance chain. But this is where
264       one of Type::Tiny's big optimizations happens. Type::Tiny can glue
265       together a bunch of checks with a stringy eval, and get a single
266       coderef that can do all the checks in one go.
267
268       This is why when Type::Tiny gives you a choice of using a coderef or a
269       string of Perl code, you should usually choose the string of Perl code.
270       A single coderef can "break the chain".
271
272       But these automatically generated strings of Perl code are not always
273       as efficient as they could be. For example, imagine that HashRef is
274       defined as:
275
276         my $Defined = Type::Tiny->new(
277           name       => 'Defined',
278           constraint => 'defined($_)',
279         );
280         my $Ref = Type::Tiny->new(
281           name       => 'Ref',
282           parent     => $Defined,
283           constraint => 'ref($_)',
284         );
285         my $HashRef = Type::Tiny->new(
286           name       => 'HashRef',
287           parent     => $Ref,
288           constraint => 'ref($_) eq "HASH"',
289         );
290
291       Then the combined check is:
292
293         defined($_) and ref($_) and ref($_) eq "HASH"
294
295       Actually in practice it's even more complicated, because Type::Tiny
296       needs to localize and set $_ first.
297
298       But in practice, the following should be a sufficient check:
299
300         ref($_) eq "HASH"
301
302       It is possible for the HashRef type to have more control over the
303       string of code generated.
304
305         my $HashRef = Type::Tiny->new(
306           name       => 'HashRef',
307           parent     => $Ref,
308           constraint => 'ref($_) eq "HASH"',
309           inlined    => sub {
310             my $varname = pop;
311             sprintf 'ref(%s) eq "HASH"', $varname;
312           },
313         );
314
315       The inlined coderef gets passed the name of a variable to check. This
316       could be '$_' or '$var' or "$some{deep}{thing}[0]". Because it is
317       passed the name of a variable to check, instead of always checking $_,
318       this enables very efficient checking for parameterized types.
319
320       Although in this case, the inlining coderef is just returning a string,
321       technically it returns a list of strings. If there's multiple strings,
322       Type::Tiny will join them together in a big "&&" statement.
323
324       As a special case, if the first item in the returned list of strings is
325       undef, then Type::Tiny will substitute the parent type constraint's
326       inlined string in its place. So an inlieing coderef for even numbers
327       might be:
328
329         Type::Tiny->new(
330           name       => 'EvenNumber',
331           parent     => Types::Standard::Int,
332           constraint => sub { $_ % 2 == 0 },
333           inlined    => sub {
334             my $varname = pop;
335             return (undef, "$varname % 2 == 0");
336           },
337         );
338
339       Even if you provide a coderef as a string, an inlining coderef has the
340       potential to generate more efficient code, so you should consider
341       providing one.
342
343   Pre-Declaring Types
344         use Type::Library -base,
345           -declare => qw( Foo Bar Baz );
346
347       This declares types Foo, Bar, and Baz at compile time so they can
348       safely be used as barewords in your type library.
349
350       This also allows recursively defined types to (mostly) work!
351
352         use Type::Library -base,
353           -declare => qw( NumericArrayRef );
354         use Types::Standard qw( Num ArrayRef );
355
356         __PACKAGE__->add_type(
357           name     => NumericArrayRef,
358           parent   => ArrayRef->of( Num | NumericArrayRef ),
359         );
360
361       (Support for recursive type definitions added in Type::Library
362       1.009_000.)
363
364   Parameterizable Types
365       This is probably the most "meta" concept that is going to be covered.
366       Building your own type constraint that can be parameterized like
367       ArrayRef or HasMethods.
368
369       The type constraint we'll build will be MultipleOf[$i] which checks
370       that an integer is a multiple of $i.
371
372         __PACKAGE__->add_type(
373           name       => 'MultipleOf',
374           parent     => Int,
375
376           # This coderef gets passed the contents of the square brackets.
377           constraint_generator => sub {
378             my $i = assert_Int(shift);
379             # needs to return a coderef to use as a constraint for the
380             # parameterized type
381             return sub { $_ % $i == 0 };
382           },
383
384           # optional but recommended
385           inline_generator => sub {
386             my $i = shift;
387             return sub {
388               my $varname = pop;
389               return (undef, "$varname % $i == 0");
390             };
391           },
392
393           # probably the most complex bit
394           coercion_generator => sub {
395             my $i = $_[2];
396             require Type::Coercion;
397             return Type::Coercion->new(
398               type_coercion_map => [
399                 Num, qq{ int($i * int(\$_/$i)) }
400               ],
401             );
402           },
403         );
404
405       Now we can define an even number like this:
406
407         __PACKAGE__->add_type(
408           name     => 'EvenNumber',
409           parent   => __PACKAGE__->get_type('MultipleOf')->of(2),
410           coercion => 1,  # inherit from parent
411         );
412
413       Note that it is possible for a type constraint to have a "constraint"
414       and a "constraint_generator".
415
416         BaseType          # uses the constraint
417         BaseType[]        # constraint_generator with no arguments
418         BaseType[$x]      # constraint_generator with an argument
419
420       In the MultipleOf example above, MultipleOf[] with no number would
421       throw an error because of "assert_Int(shift)" not finding an integer.
422
423       But it is certainly possible for BaseType[] to be meaningful and
424       distinct from "BaseType".
425
426       For example, Tuple is just the same as ArrayRef and accepts any
427       arrayref as being valid. But Tuple[] will only accept arrayrefs with
428       zero elements in them. (Just like Tuple[Any,Any] will only accept
429       arrayrefs with two elements.)
430

NEXT STEPS

432       After that last example, probably have a little lie down. Once you're
433       recovered, here's your next step:
434
435       •   Type::Tiny::Manual::UsingWithMoose
436
437           How to use Type::Tiny with Moose, including the advantages of
438           Type::Tiny over built-in type constraints, and Moose-specific
439           features.
440

AUTHOR

442       Toby Inkster <tobyink@cpan.org>.
443
445       This software is copyright (c) 2013-2014, 2017-2021 by Toby Inkster.
446
447       This is free software; you can redistribute it and/or modify it under
448       the same terms as the Perl 5 programming language system itself.
449

DISCLAIMER OF WARRANTIES

451       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
452       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
453       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
454
455
456
457perl v5.34.0                      2022-01-21  Type::Tiny::Manual::Libraries(3)
Impressum