1Type::Tiny::Manual::OptUismeirzaCtoinotnr(i3b)uted PerlTDyopceu:m:eTnitnayt:i:oMnanual::Optimization(3)
2
3
4
6 Type::Tiny::Manual::Optimization - squeeze the most out of your CPU
7
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, but parameterized HashLike and
54 ArrayLike will not.
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 use Types::Standard qw( Num Object );
216 use Type::Params qw( compile );
217 use Devel::StrictMode qw( STRICT );
218
219 sub add_number {
220 state $check;
221 $check = compile(Object, Num) if STRICT;
222
223 my ($self, $num) = STRICT ? $check->(@_) : @_;
224 push @{ $self->numbers }, $num;
225 return $self;
226 }
227
228 Again, you need to be careful to ensure consistent behaviour if you're
229 using coercions, defaults, slurpies, etc.
230
231 Ad-Hoc Type Checks
232
233 ...;
234 my $x = get_some_number();
235 assert_Int($x) if STRICT;
236 return $x + 1;
237 ...;
238
240 Here's your next step:
241
242 • Type::Tiny::Manual::Coercions
243
244 Advanced information on coercions.
245
247 Toby Inkster <tobyink@cpan.org>.
248
250 This software is copyright (c) 2013-2014, 2017-2021 by Toby Inkster.
251
252 This is free software; you can redistribute it and/or modify it under
253 the same terms as the Perl 5 programming language system itself.
254
256 THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
257 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
258 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
259
260
261
262perl v5.34.0 2022-01-21Type::Tiny::Manual::Optimization(3)