File Coverage

blib/lib/Signature/Attribute/Checked.pm
Criterion Covered Total %
statement 6 7 85.7
branch n/a
condition n/a
subroutine 3 4 75.0
pod n/a
total 9 11 81.8


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2023-2024 -- leonerd@leonerd.org.uk
5              
6             package Signature::Attribute::Checked 0.06;
7              
8 6     6   1741503 use v5.14;
  6         23  
9 6     6   42 use warnings;
  6         15  
  6         1001  
10              
11             require XSLoader;
12             XSLoader::load( __PACKAGE__, our $VERSION );
13              
14             =head1 NAME
15              
16             C - apply value constraint checks to subroutine parameters
17              
18             =head1 SYNOPSIS
19              
20             With L:
21              
22             use v5.26;
23             use Sublike::Extended;
24             use Signature::Attribute::Checked;
25             use Data::Checks qw( Num );
26              
27             extended sub add ($x :Checked(Num), $y :Checked(Num)) {
28             return $x + $y;
29             }
30              
31             say add(10, 20); # this is fine
32              
33             say add("hello", "world"); # throws an exception
34              
35             =head1 DESCRIPTION
36              
37             This module provides a third-party subroutine parameter attribute via
38             L, which declares that values passed to a subroutine must
39             conform to a given constraint check.
40              
41             B The ability for sublike constructions to take third-party parameter
42             attributes is still new and highly experimental, and subject to much API
43             change in future. As a result, this module should be considered equally
44             experimental. Core perl's parser does not permit parameters to take
45             attributes. This ability must be requested specially; either by using
46             L, or perhaps enabled directly by some other sublike
47             keyword using the C infrastructure.
48              
49             Additionally, the behaviour provided by this module should be considered more
50             of a work-in-progress stepping stone. Ideally, constraint syntax ought
51             to be provided in a much more fundamental way by Perl itself, allowing it to
52             be used on C lexicals, class fields, and other places as well as
53             subroutine parameters. This module is more of a placeholder to allow some part
54             of that behaviour to be specified for subroutine parameters, while not getting
55             in the way of a more general, more powerful system being added in future.
56              
57             =head1 PARAMETER ATTRIBUTES
58              
59             =head2 :Checked
60              
61             extended sub f($x :Checked(EXPRESSION)) { ... }
62              
63             Declares that any value passed to the parameter at the time the subroutine is
64             called must conform to the constraint checker specified by the expression.
65             Attempts to pass a non-conforming value will throw an exception and the
66             subroutine body will not be invoked. Currently only scalar parameters are
67             supported.
68              
69             At compiletime, the string given by I is C'ed in scalar
70             context, and its result is stored as part of the subroutine's definition. The
71             expression must yield a value usable by L. Namely, one of:
72              
73             =over 4
74              
75             =item *
76              
77             Any of the constraint checkers provided by the L module itself.
78              
79             =item *
80              
81             An B reference with a C method:
82              
83             $ok = $checkerobj->check( $value );
84              
85             =item *
86              
87             A B giving the name of a package with a C method:
88              
89             $ok = $checkerpkg->check( $value );
90              
91             If using a plain package name as a checker, be sure to quote package names so
92             it will not upset C.
93              
94             extended sub xyz ($x :Checked('CheckerPackage')) { ... }
95              
96             =back
97              
98             As this is the interface supported by L, any constraint
99             object provided by that module is already supported here as well.
100              
101             use Types::Standard qw( Str Num );
102              
103             extended sub ghi ($x :Checked(Str), $y :Checked(Num)) { ... }
104              
105             At runtime, this constraint checker is used every time an attempt is made to
106             call the function. The checker is used as the invocant for invoking a C
107             method, and the value for the parameter is passed as an argument. If the
108             method returns true, the call is allowed. If false, it is rejected with an
109             exception and the function body is not invoked.
110              
111             (For performance reasons, the C method is actually resolved into a
112             function at compiletime when the C<:Checked> attribute is applied, and this
113             stored function is the one that is called at assignment time. If the method
114             itself is replaced later by globref assignment or other trickery, this updated
115             function will not be used.)
116              
117             It is not specified what order these checks are performed in. In particular,
118             if any parameter default expressions invoke any side-effects, it is
119             unspecified whether such side-effects will happen if a value passed for a
120             parameter fails its constraint check. Users should take care not to attempt to
121             invoke any side-effects during such expressions.
122              
123             Note further that these value checks are only performed once, at the time the
124             subroutine is invoked. Code within the body of the subroutine can freely
125             assign any other kind of value to the variable corresponding to a C<:Checked>
126             parameter without issue.
127              
128             extended sub foo ($n :Checked(Num)) {
129             $x = "seven"; # this is permitted
130             }
131              
132             =cut
133              
134             sub import
135             {
136 5     5   267 $^H{"Signature::Attribute::Checked/Checked"}++;
137             }
138              
139             sub unimport
140             {
141 0     0     delete $^H{"Signature::Attribute::Checked/Checked"};
142             }
143              
144             =head1 SEE ALSO
145              
146             =over 4
147              
148             =item *
149              
150             L - apply value constraint checks to C fields
151              
152             =back
153              
154             =head1 AUTHOR
155              
156             Paul Evans
157              
158             =cut
159              
160             0x55AA;