1Specio(3) User Contributed Perl Documentation Specio(3)
2
3
4
6 Specio - Type constraints and coercions for Perl
7
9 version 0.48
10
12 package MyApp::Type::Library;
13
14 use Specio::Declare;
15 use Specio::Library::Builtins;
16
17 declare(
18 'PositiveInt',
19 parent => t('Int'),
20 inline => sub {
21 $_[0]->parent->inline_check( $_[1] )
22 . ' && ( '
23 . $_[1]
24 . ' > 0 )';
25 },
26 );
27
28 # or ...
29
30 declare(
31 'PositiveInt',
32 parent => t('Int'),
33 where => sub { $_[0] > 0 },
34 );
35
36 declare(
37 'ArrayRefOfPositiveInt',
38 parent => t(
39 'ArrayRef',
40 of => t('PositiveInt'),
41 ),
42 );
43
44 coerce(
45 'ArrayRefOfPositiveInt',
46 from => t('PositiveInt'),
47 using => sub { [ $_[0] ] },
48 );
49
50 any_can_type(
51 'Duck',
52 methods => [ 'duck_walk', 'quack' ],
53 );
54
55 object_isa_type('MyApp::Person');
56
58 The "Specio" distribution provides classes for representing type
59 constraints and coercion, along with syntax sugar for declaring them.
60
61 Note that this is not a proper type system for Perl. Nothing in this
62 distribution will magically make the Perl interpreter start checking a
63 value's type on assignment to a variable. In fact, there's no built-in
64 way to apply a type to a variable at all.
65
66 Instead, you can explicitly check a value against a type, and
67 optionally coerce values to that type.
68
69 My long-term goal is to replace Moose's built-in types and
70 MooseX::Types with this module.
71
73 At it's core, a type is simply a constraint. A constraint is code that
74 checks a value and returns true or false. Most constraints are
75 represented by Specio::Constraint::Simple objects. However, there are
76 other type constraint classes for specialized kinds of constraints.
77
78 Types can be named or anonymous, and each type can have a parent type.
79 A type's constraint is optional because sometimes you may want to
80 create a named subtype of some existing type without adding additional
81 constraints.
82
83 Constraints can be expressed either in terms of a simple subroutine
84 reference or in terms of an inline generator subroutine reference. The
85 former is easier to write but the latter is preferred because it allow
86 for better optimization.
87
88 A type can also have an optional message generator subroutine
89 reference. You can use this to provide a more intelligent error message
90 when a value does not pass the constraint, though the default message
91 should suffice for most cases.
92
93 Finally, you can associate a set of coercions with a type. A coercion
94 is a subroutine reference (or inline generator, like constraints), that
95 takes a value of one type and turns it into a value that matches the
96 type the coercion belongs to.
97
99 This distribution ships with a set of builtin types representing the
100 types provided by the Perl interpreter itself. They are arranged in a
101 hierarchy as follows:
102
103 Item
104 Bool
105 Maybe (of `a)
106 Undef
107 Defined
108 Value
109 Str
110 Num
111 Int
112 ClassName
113 Ref
114 ScalarRef (of `a)
115 ArrayRef (of `a)
116 HashRef (of `a)
117 CodeRef
118 RegexpRef
119 GlobRef
120 FileHandle
121 Object
122
123 The "Item" type accepts anything and everything.
124
125 The "Bool" type only accepts "undef", 0, or 1.
126
127 The "Undef" type only accepts "undef".
128
129 The "Defined" type accepts anything except "undef".
130
131 The "Num" and "Int" types are stricter about numbers than Perl is.
132 Specifically, they do not allow any sort of space in the number, nor do
133 they accept "Nan", "Inf", or "Infinity".
134
135 The "ClassName" type constraint checks that the name is valid and that
136 the class is loaded.
137
138 The "FileHandle" type accepts either a glob, a scalar filehandle, or
139 anything that isa IO::Handle.
140
141 All types accept overloaded objects that support the required
142 operation. See below for details.
143
144 Overloading
145 Perl's overloading is horribly broken and doesn't make much sense at
146 all.
147
148 However, unlike Moose, all type constraints allow overloaded objects
149 where they make sense.
150
151 For types where overloading makes sense, we explicitly check that the
152 object provides the type overloading we expect. We do not simply try to
153 use the object as the type in question and hope it works. This means
154 that these checks effectively ignore the "fallback" setting for the
155 overloaded object. In other words, an object that overloads
156 stringification will not pass the "Bool" type check unless it also
157 overloads boolification.
158
159 Most types do not check that the overloaded method actually returns
160 something that matches the constraint. This may change in the future.
161
162 The "Bool" type accepts an object that implements "bool" overloading.
163
164 The "Str" type accepts an object that implements string ("q{""}")
165 overloading.
166
167 The "Num" type accepts an object that implements numeric ("'0+'}")
168 overloading. The "Int" type does as well, but it will check that the
169 overloading returns an actual integer.
170
171 The "ClassName" type will accept an object with string overloading that
172 returns a class name.
173
174 To make this all more confusing, the "Value" type will never accept an
175 object, even though some of its subtypes will.
176
177 The various reference types all accept objects which provide the
178 appropriate overloading. The "FileHandle" type accepts an object which
179 overloads globification as long as the returned glob is an open
180 filehandle.
181
183 Any type followed by a type parameter "of `a" in the hierarchy above
184 can be parameterized. The parameter is itself a type, so you can say
185 you want an "ArrayRef of Int", or even an "ArrayRef of HashRef of
186 ScalarRef of ClassName".
187
188 When they are parameterized, the "ScalarRef" and "ArrayRef" types check
189 that the value(s) they refer to match the type parameter. For the
190 "HashRef" type, the parameter applies to the values (keys are never
191 checked).
192
193 Maybe
194 The "Maybe" type is a special parameterized type. It allows for either
195 "undef" or a value. All by itself, it is meaningless, since it is
196 equivalent to "Maybe of Item", which is equivalent to Item. When
197 parameterized, it accepts either an "undef" or the type of its
198 parameter.
199
200 This is useful for optional attributes or parameters. However, you're
201 probably better off making your code simply not pass the parameter at
202 all This usually makes for a simpler API.
203
205 Types are local to each package where they are used. When you "import"
206 types from some other library, you are actually making a copy of that
207 type.
208
209 This means that a type named "Foo" in one package may not be the same
210 as "Foo" in another package. This has potential for confusion, but it
211 also avoids the magic action at a distance pollution that comes with a
212 global type naming system.
213
214 The registry is managed internally by the Specio distribution's
215 modules, and is not exposed to your code. To access a type, you always
216 call t('TypeName').
217
218 This returns the named type or dies if no such type exists.
219
220 Because types are always copied on import, it's safe to create
221 coercions on any type. Your coercion from "Str" to "Int" will not be
222 seen by any other package, unless that package explicitly imports your
223 "Int" type.
224
225 When you import types, you import every type defined in the package you
226 import from. However, you can overwrite an imported type with your own
227 type definition. You cannot define the same type twice internally.
228
230 By default, all types created inside a package are invisible to other
231 packages. If you want to create a type library, you need to inherit
232 from Specio::Exporter package:
233
234 package MyApp::Type::Library;
235
236 use parent 'Specio::Exporter';
237
238 use Specio::Declare;
239 use Specio::Library::Builtins;
240
241 declare(
242 'Foo',
243 parent => t('Str'),
244 where => sub { $_[0] =~ /foo/i },
245 );
246
247 Now the MyApp::Type::Library package will export a single type named
248 "Foo". It does not re-export the types provided by
249 Specio::Library::Builtins.
250
251 If you want to make your library re-export some other libraries types,
252 you can ask for this explicitly:
253
254 package MyApp::Type::Library;
255
256 use parent 'Specio::Exporter';
257
258 use Specio::Declare;
259 use Specio::Library::Builtins -reexport;
260
261 declare( 'Foo, ... );
262
263 Now MyApp::Types::Library exports any types it defines, as well as all
264 the types defined in Specio::Library::Builtins.
265
267 Use the Specio::Declare module to declare types. It exports a set of
268 helpers for declaring types. See that module's documentation for more
269 details on these helpers.
270
272 This should just work. Use a Specio type anywhere you'd specify a type.
273
275 Using Specio with Moo is easy. You can pass Specio constraint objects
276 as "isa" parameters for attributes. For coercions, simply call
277 "$type->coercion_sub".
278
279 package Foo;
280
281 use Specio::Declare;
282 use Specio::Library::Builtins;
283 use Moo;
284
285 my $str_type = t('Str');
286 has string => (
287 is => 'ro',
288 isa => $str_type,
289 );
290
291 my $ucstr = declare(
292 'UCStr',
293 parent => t('Str'),
294 where => sub { $_[0] =~ /^[A-Z]+$/ },
295 );
296
297 coerce(
298 $ucstr,
299 from => t('Str'),
300 using => sub { return uc $_[0] },
301 );
302
303 has ucstr => (
304 is => 'ro',
305 isa => $ucstr,
306 coerce => $ucstr->coercion_sub,
307 );
308
309 The subs returned by Specio use Sub::Quote internally and are suitable
310 for inlining.
311
313 See Specio::Constraint::Simple for the API that all constraint objects
314 share.
315
317 This module aims to supplant both Moose's built-in type system (see
318 Moose::Util::TypeConstraints aka MUTC) and MooseX::Types, which
319 attempts to patch some of the holes in the Moose built-in type design.
320
321 Here are some of the salient differences:
322
323 • Types names are strings, but they're not global
324
325 Unlike Moose and MooseX::Types, type names are always local to the
326 current package. There is no possibility of name collision between
327 different modules, so you can safely use short type names.
328
329 Unlike MooseX::Types, types are strings, so there is no possibility
330 of colliding with existing class or subroutine names.
331
332 • No type auto-creation
333
334 Types are always retrieved using the t() subroutine. If you pass an
335 unknown name to this subroutine it dies. This is different from
336 Moose and MooseX::Types, which assume that unknown names are class
337 names.
338
339 • Anon types are explicit
340
341 With Moose and MooseX::Types, you use the same subroutine,
342 subtype(), to declare both named and anonymous types. With Specio,
343 you use declare() for named types and anon() for anonymous types.
344
345 • Class and object types are separate
346
347 Moose and MooseX::Types have "class_type" and "duck_type". The
348 former type requires an object, while the latter accepts a class
349 name or object.
350
351 With Specio, the distinction between accepting an object versus
352 object or class is explicit. There are six declaration helpers,
353 "object_can_type", "object_does_type", "object_isa_type",
354 "any_can_type", "any_does_type", and "any_isa_type".
355
356 • Overloading support is baked in
357
358 Perl's overloading is quite broken but ignoring it makes Moose's
359 type system frustrating to use in many cases.
360
361 • Types can either have a constraint or inline generator, not both
362
363 Moose and MooseX::Types types can be defined with a subroutine
364 reference as the constraint, an inline generator subroutine, or
365 both. This is purely for backwards compatibility, and it makes the
366 internals more complicated than they need to be.
367
368 With Specio, a constraint can have either a subroutine reference or
369 an inline generator, not both.
370
371 • Coercions can be inlined
372
373 I simply never got around to implementing this in Moose.
374
375 • No crazy coercion features
376
377 Moose has some bizarre (and mostly) undocumented features relating
378 to coercions and parameterizable types. This is a misfeature.
379
381 There are several optional prereqs that if installed will make this
382 distribution better in some way.
383
384 • Ref::Util
385
386 Installing this will speed up a number of type checks for built-in
387 types.
388
389 • XString
390
391 If this is installed it will be loaded instead of the B module if
392 you have Perl 5.10 or greater. This module is much more memory
393 efficient than loading all of B.
394
395 • Sub::Util or Sub::Name
396
397 If one of these is installed then stack traces that end up in
398 Specio code will have much better subroutine names for any frames.
399
401 This distro was originally called "Type", but that's an awfully generic
402 top level namespace. Specio is Latin for for "look at" and "spec" is
403 the root for the word "species". It's short, relatively easy to type,
404 and not used by any other distro.
405
407 Eventually I'd like to see this distro replace Moose's internal type
408 system, which would also make MooseX::Types obsolete.
409
411 Bugs may be submitted at
412 <https://github.com/houseabsolute/Specio/issues>.
413
415 The source code repository for Specio can be found at
416 <https://github.com/houseabsolute/Specio>.
417
419 If you'd like to thank me for the work I've done on this module, please
420 consider making a "donation" to me via PayPal. I spend a lot of free
421 time creating free software, and would appreciate any support you'd
422 care to offer.
423
424 Please note that I am not suggesting that you must do this in order for
425 me to continue working on this particular software. I will continue to
426 do so, inasmuch as I have in the past, for as long as it interests me.
427
428 Similarly, a donation made in this way will probably not make me work
429 on this software much more, unless I get so many donations that I can
430 consider working on free software full time (let's all have a chuckle
431 at that together).
432
433 To donate, log into PayPal and send money to autarch@urth.org, or use
434 the button at <https://www.urth.org/fs-donation.html>.
435
437 Dave Rolsky <autarch@urth.org>
438
440 • Chris White <chrisw@leehayes.com>
441
442 • cpansprout <cpansprout@gmail.com>
443
444 • Graham Knop <haarg@haarg.org>
445
446 • Karen Etheridge <ether@cpan.org>
447
448 • Vitaly Lipatov <lav@altlinux.ru>
449
451 This software is Copyright (c) 2012 - 2022 by Dave Rolsky.
452
453 This is free software, licensed under:
454
455 The Artistic License 2.0 (GPL Compatible)
456
457 The full text of the license can be found in the LICENSE file included
458 with this distribution.
459
460
461
462perl v5.38.0 2023-07-21 Specio(3)