1Type::Tiny::Manual::OptUismeirzaCtoinotnr(i3b)uted PerlTDyopceu:m:eTnitnayt:i:oMnanual::Optimization(3)
2
3
4

NAME

6       Type::Tiny::Manual::Optimization - squeeze the most out of your CPU
7

MANUAL

9       Type::Tiny is written with efficiency in mind, but there are techniques
10       you can use to get the best performance out of it.
11
12   XS
13       The simplest thing you can do to increase performance of many of the
14       built-in type constraints is to install Type::Tiny::XS, a set of ultra-
15       fast type constraint checks implemented in C.
16
17       Type::Tiny will attempt to load Type::Tiny::XS and use its type checks.
18       If Type::Tiny::XS is not available, it will then try to use Mouse if it
19       is already loaded, but Type::Tiny won't attempt to load Mouse for you.
20
21       Certain type constraints can also be accelerated if you have
22       Ref::Util::XS installed.
23
24       Types that can be accelerated by Type::Tiny::XS
25
26       The following simple type constraints from Types::Standard will be
27       accelerated by Type::Tiny::XS: Any, ArrayRef, Bool, ClassName, CodeRef,
28       Defined, FileHandle, GlobRef, HashRef, Int, Item, Object, Map, Ref,
29       ScalarRef, Str, Tuple, Undef, and Value. (Note that Num and RegexpRef
30       are not on that list.)
31
32       The parameterized form of Ref cannot be accelerated.
33
34       The parameterized forms of ArrayRef, HashRef, and Map can be
35       accelerated only if their parameters are.
36
37       The parameterized form of Tuple can be accelerated if its parameters
38       are, it has no Optional components, and it does not use Slurpy.
39
40       Certain type constraints may benefit partially from Type::Tiny::XS.
41       For example, RoleName inherits from ClassName, so part of the type
42       check will be conducted by Type::Tiny::XS.
43
44       The parameterized InstanceOf, HasMethods, and Enum type constraints
45       will be accelerated. So will Type::Tiny::Class, Type::Tiny::Duck, and
46       Type::Tiny::Enum objects.
47
48       The PositiveInt and PositiveOrZeroInt type constraints from
49       Types::Common::Numeric will be accelerated, as will the NonEmptyStr
50       type constraint from Types::Common::String.
51
52       The StringLike, CodeLike, HashLike, and ArrayLike types from
53       Types::TypeTiny will be accelerated, including the parameterized
54       versions of HashLike and ArrayLike.
55
56       Type::Tiny::Union and Type::Tiny::Intersection will also be accelerated
57       if their constituent type constraints are.
58
59       Types that can be accelerated by Mouse
60
61       The following simple type constraints from Types::Standard will be
62       accelerated by Type::Tiny::XS: Any, ArrayRef, Bool, ClassName, CodeRef,
63       Defined, FileHandle, GlobRef, HashRef, Ref, ScalarRef, Str, Undef, and
64       Value.  (Note that Item, Num, Int, Object, and RegexpRef are not on
65       that list.)
66
67       The parameterized form of Ref cannot be accelerated.
68
69       The parameterized forms of ArrayRef and HashRef can be accelerated only
70       if their parameters are.
71
72       Certain type constraints may benefit partially from Mouse. For example,
73       RoleName inherits from ClassName, so part of the type check will be
74       conducted by Mouse.
75
76       The parameterized InstanceOf and HasMethods type constraints will be
77       accelerated. So will Type::Tiny::Class and Type::Tiny::Duck objects.
78
79   Inlining Type Constraints
80       In the case of a type constraint like this:
81
82        my $type = Int->where( sub { $_ >= 0 } );
83
84       Type::Tiny will need to call one sub to verify a value meets the Int
85       type constraint, and your coderef to check that the value is above
86       zero.
87
88       Sub calls in Perl are relatively expensive in terms of memory and CPU
89       usage, so it would be good if it could be done all in one sub call.
90
91       The Int type constraint knows how to create a string of Perl code that
92       checks an integer. It's something like the following. (It's actually
93       more complicated, but this is close enough as an example.)
94
95        $_ =~ /^-?[0-9]+$/
96
97       If you provide your check as a string instead of a coderef, like this:
98
99        my $type = Int->where( q{ $_ >= 0 } );
100
101       Then Type::Tiny will be able to combine them into one string:
102
103        ( $_ =~ /^-?[0-9]+$/ ) && ( $_ >= 0 )
104
105       So Type::Tiny will be able to check values in one sub call. Providing
106       constraints as strings is a really simple and easy way of optimizing
107       type checks.
108
109       But it can be made even more efficient. Type::Tiny needs to localize $_
110       and copy the value into it for the above check. If you're checking
111       ArrayRef[$type] this will be done for each element of the array. Things
112       could be made more efficient if Type::Tiny were able to directly check:
113
114        ( $arrayref->[$i] =~ /^-?[0-9]+$/ ) && ( $arrayref->[$i] >= 0 )
115
116       This can be done by providing an inlining sub. The sub is given a
117       variable name and can use that in the string of code it generates.
118
119        my $type = Type::Tiny->new(
120          parent  => Int,
121          inlined => sub {
122            my ( $self, $varname ) = @_;
123            return sprintf(
124              '(%s) && ( %s >= 0 )',
125              $self->parent->inline_check( $varname ),
126              $varname,
127            );
128          }
129        );
130
131       Because it's pretty common to want to call your parent's inline check
132       and "&&" your own string with it, Type::Tiny provides a shortcut for
133       this.  Just return a list of strings to smush together with "&&", and
134       if the first one is "undef", Type::Tiny will fill in the blank with the
135       parent type check.
136
137        my $type = Type::Tiny->new(
138          parent  => Int,
139          inlined => sub {
140            my ( $self, $varname ) = @_;
141            return (
142              undef,
143              sprintf( '%s >= 0', $varname ),
144            );
145          }
146        );
147
148       There is one further optimization which can be applied to this
149       particular case. You'll note that we're checking the string matches
150       "/^-?[0-9+]$/" and then checking it's greater than or equal to zero.
151       But a non-negative integer won't ever start with a minus sign, so we
152       could inline the check to something like:
153
154        $_ =~ /^[0-9]+$/
155
156       While an inlined check can call its parent type check, it is not
157       required to.
158
159        my $type = Type::Tiny->new(
160          parent  => Int,
161          inlined => sub {
162            my ( $self, $varname ) = @_;
163            return sprintf( '%s =~ /^[0-9]+$/', $varname );
164          }
165        );
166
167       If you opt not to call the parent type check, then you need to ensure
168       your own check is at least as rigorous.
169
170   Inlining Coercions
171       Moo is the only object-oriented programming toolkit that fully supports
172       coercions being inlined, but even for Moose and Mouse, providing
173       coercions as strings can help Type::Tiny optimize its coercion
174       features.
175
176       For Moo, if you want your coercion to be inlinable, all the types
177       you're coercing from and to need to be inlinable, plus the coercion
178       needs to be given as a string of Perl code.
179
180   Common Sense
181       The HashRef[ArrayRef] type constraint can probably be checked faster
182       than HashRef[ArrayRef[Num]]. If you find yourself using very complex
183       and slow type constraints, you should consider switching to simpler and
184       faster ones. (Though this means you have to place a little more trust
185       in your caller to not supply you with bad data.)
186
187       (A counter-intuitive exception to this: even though Int is more
188       restrictive than Num, in most circumstances Int checks will run
189       faster.)
190
191   Devel::StrictMode
192       One possibility is to use strict type checks when you're running your
193       release tests, and faster, more permissive type checks at other times.
194       Devel::StrictMode can make this easier.
195
196       This provides a "STRICT" constant that indicates whether your code is
197       operating in "strict mode" based on certain environment variables.
198
199       Attributes
200
201        use Types::Standard qw( ArrayRef Num );
202        use Devel::StrictMode qw( STRICT );
203
204        has numbers => (
205          is      => 'ro',
206          isa     => STRICT ? ArrayRef[Num] : ArrayRef,
207          default => sub { [] },
208        );
209
210       It is inadvisible to do this on attributes that have coercions because
211       it can lead to inconsistent and unpredictable behaviour.
212
213       Type::Params
214
215       Very efficient way which avoids compiling the signature at all if
216       "STRICT" is false:
217
218        use Types::Standard qw( Num Object );
219        use Type::Params qw( signature );
220        use Devel::StrictMode qw( STRICT );
221
222        sub add_number {
223          state $check;
224          STRICT and $check //= signature(
225            method     => 1,
226            positional => [ Num ],
227          );
228
229          my ( $self, $num ) = STRICT ? &$check : @_;
230
231          push @{ $self->numbers }, $num;
232          return $self;
233        }
234
235       Again, you need to be careful to ensure consistent behaviour if you're
236       using coercions, defaults, slurpies, etc.
237
238       Less efficient way, but more declarative and smart enough to just
239       disable checks which are safe(ish) to disable, while coercions,
240       defaults, and slurpies will continue to work:
241
242        use Types::Standard qw( Num Object );
243        use Type::Params qw( signature );
244        use Devel::StrictMode qw( STRICT );
245
246        sub add_number {
247          state $check = signature(
248            strictness => STRICT,
249            method     => 1,
250            positional => [ Num ],
251          );
252
253          my ( $self, $num ) = &$check;
254
255          push @{ $self->numbers }, $num;
256          return $self;
257        }
258
259       Ad-Hoc Type Checks
260
261        ...;
262        my $x = get_some_number();
263        assert_Int($x) if STRICT;
264        return $x + 1;
265        ...;
266
267   The Slash Operator
268       Type::Tiny has some of the same logic as Devel::StrictMode built in.
269       In particular, it overloads the slash (division) operator so that
270       TypeA/TypeB evaluates to TypeB normally, but to TypeA in strict mode.
271
272       An example using this feature:
273
274        use Types::Standard -types;
275
276        has numbers => (
277          is      => 'ro',
278          isa     => ArrayRef[ Num / Any ],
279          default => sub { [] },
280        );
281
282       In strict mode, this attribute would check that its value is an
283       arrayref of numbers (which may be slow if it contains a lot of
284       numbers). Normally though, it will just check that the value is an
285       arrayref.
286

NEXT STEPS

288       Here's your next step:
289
290       •   Type::Tiny::Manual::Coercions
291
292           Advanced information on coercions.
293

AUTHOR

295       Toby Inkster <tobyink@cpan.org>.
296
298       This software is copyright (c) 2013-2014, 2017-2023 by Toby Inkster.
299
300       This is free software; you can redistribute it and/or modify it under
301       the same terms as the Perl 5 programming language system itself.
302

DISCLAIMER OF WARRANTIES

304       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
305       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
306       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
307
308
309
310perl v5.38.0                      2023-07-21Type::Tiny::Manual::Optimization(3)
Impressum