Filename | /Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Feature/Compat/Try.pm |
Statements | Executed 33 statements in 809µs |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 2.13ms | 2.69ms | BEGIN@13 | Feature::Compat::Try::
6 | 6 | 6 | 40µs | 192µs | import | Feature::Compat::Try::
1 | 1 | 1 | 33µs | 33µs | BEGIN@8 | Feature::Compat::Try::
1 | 1 | 1 | 10µs | 65µs | BEGIN@9 | Feature::Compat::Try::
1 | 1 | 1 | 6µs | 6µs | BEGIN@10 | Feature::Compat::Try::
Line | State ments |
Time on line |
Calls | Time in subs |
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, 2021-2022 -- leonerd@leonerd.org.uk | ||||
5 | |||||
6 | package Feature::Compat::Try 0.05; | ||||
7 | |||||
8 | 2 | 51µs | 1 | 33µs | # spent 33µs within Feature::Compat::Try::BEGIN@8 which was called:
# once (33µs+0s) by OpenAPI::Modern::BEGIN@23 at line 8 # spent 33µs making 1 call to Feature::Compat::Try::BEGIN@8 |
9 | 2 | 45µs | 2 | 120µs | # spent 65µs (10+55) within Feature::Compat::Try::BEGIN@9 which was called:
# once (10µs+55µs) by OpenAPI::Modern::BEGIN@23 at line 9 # spent 65µs making 1 call to Feature::Compat::Try::BEGIN@9
# spent 55µs making 1 call to warnings::import |
10 | 2 | 40µs | 1 | 6µs | # spent 6µs within Feature::Compat::Try::BEGIN@10 which was called:
# once (6µs+0s) by OpenAPI::Modern::BEGIN@23 at line 10 # spent 6µs making 1 call to Feature::Compat::Try::BEGIN@10 |
11 | |||||
12 | # Core's use feature 'try' only supports 'finally' since 5.35.8 | ||||
13 | 2 | 622µs | 2 | 2.83ms | # spent 2.69ms (2.13+560µs) within Feature::Compat::Try::BEGIN@13 which was called:
# once (2.13ms+560µs) by OpenAPI::Modern::BEGIN@23 at line 13 # spent 2.69ms making 1 call to Feature::Compat::Try::BEGIN@13
# spent 144µs making 1 call to constant::import |
14 | |||||
15 | =head1 NAME | ||||
16 | |||||
17 | C<Feature::Compat::Try> - make C<try/catch> syntax available | ||||
18 | |||||
19 | =head1 SYNOPSIS | ||||
20 | |||||
21 | use Feature::Compat::Try; | ||||
22 | |||||
23 | sub foo | ||||
24 | { | ||||
25 | try { | ||||
26 | attempt_a_thing(); | ||||
27 | return "success"; | ||||
28 | } | ||||
29 | catch ($e) { | ||||
30 | warn "It failed - $e"; | ||||
31 | return "failure"; | ||||
32 | } | ||||
33 | } | ||||
34 | |||||
35 | =head1 DESCRIPTION | ||||
36 | |||||
37 | This module makes syntax support for C<try/catch> control flow easily | ||||
38 | available. | ||||
39 | |||||
40 | Perl added such syntax at version 5.34.0, and extended it to support optional | ||||
41 | C<finally> blocks at 5.35.9, which is enabled by | ||||
42 | |||||
43 | use feature 'try'; | ||||
44 | |||||
45 | On that version of perl or later, this module simply enables the core feature | ||||
46 | equivalent to using it directly. On such perls, this module will install with | ||||
47 | no non-core dependencies, and requires no C compiler. | ||||
48 | |||||
49 | On older versions of perl before such syntax is available, it is currently | ||||
50 | provided instead using the L<Syntax::Keyword::Try> module, imported with a | ||||
51 | special set of options to configure it to recognise exactly and only the same | ||||
52 | syntax as the core perl feature, thus ensuring that any code using it will | ||||
53 | still continue to function on that newer perl. | ||||
54 | |||||
55 | =cut | ||||
56 | |||||
57 | =head1 KEYWORDS | ||||
58 | |||||
59 | =head2 try | ||||
60 | |||||
61 | try { | ||||
62 | STATEMENTS... | ||||
63 | } | ||||
64 | ... | ||||
65 | |||||
66 | A C<try> statement provides the main body of code that will be invoked, and | ||||
67 | must be followed by a C<catch> statement. It may optionally be followed by | ||||
68 | a C<finally> statement. | ||||
69 | |||||
70 | Execution of the C<try> statement itself begins from the block given to the | ||||
71 | statement and continues until either it throws an exception, or completes | ||||
72 | successfully by reaching the end of the block. | ||||
73 | |||||
74 | The body of a C<try {}> block may contain a C<return> expression. If executed, | ||||
75 | such an expression will cause the entire containing function to return with | ||||
76 | the value provided. This is different from a plain C<eval {}> block, in which | ||||
77 | circumstance only the C<eval> itself would return, not the entire function. | ||||
78 | |||||
79 | The body of a C<try {}> block may contain loop control expressions (C<redo>, | ||||
80 | C<next>, C<last>) which will have their usual effect on any loops that the | ||||
81 | C<try {}> block is contained by. | ||||
82 | |||||
83 | The parsing rules for the set of statements (the C<try> block and its | ||||
84 | associated C<catch>) are such that they are parsed as a self-contained | ||||
85 | statement. Because of this, there is no need to end with a terminating | ||||
86 | semicolon. | ||||
87 | |||||
88 | Even though it parses as a statement and not an expression, a C<try> block can | ||||
89 | still yield a value if it appears as the final statement in its containing | ||||
90 | C<sub> or C<do> block. For example: | ||||
91 | |||||
92 | my $result = do { | ||||
93 | try { attempt_func() } | ||||
94 | catch ($e) { "Fallback Value" } | ||||
95 | }; | ||||
96 | |||||
97 | =head2 catch | ||||
98 | |||||
99 | ... | ||||
100 | catch ($var) { | ||||
101 | STATEMENTS... | ||||
102 | } | ||||
103 | |||||
104 | A C<catch> statement provides a block of code to the preceding C<try> | ||||
105 | statement that will be invoked in the case that the main block of code throws | ||||
106 | an exception. A new lexical variable is created to store the exception in. | ||||
107 | |||||
108 | Presence of this C<catch> statement causes any exception thrown by the | ||||
109 | preceding C<try> block to be non-fatal to the surrounding code. If the | ||||
110 | C<catch> block wishes to optionally handle some exceptions but not others, it | ||||
111 | can re-raise it (or another exception) by calling C<die> in the usual manner. | ||||
112 | |||||
113 | As with C<try>, the body of a C<catch {}> block may also contain a C<return> | ||||
114 | expression, which as before, has its usual meaning, causing the entire | ||||
115 | containing function to return with the given value. The body may also contain | ||||
116 | loop control expressions (C<redo>, C<next> or C<last>) which also have their | ||||
117 | usual effect. | ||||
118 | |||||
119 | =head2 finally | ||||
120 | |||||
121 | ... | ||||
122 | finally { | ||||
123 | STATEMENTS... | ||||
124 | } | ||||
125 | |||||
126 | A C<finally> statement provides an optional block of code to the preceding | ||||
127 | C<try>/C<catch> pair which is executed afterwards, both in the case of a | ||||
128 | normal execution or a thrown exception. This code block may be used to | ||||
129 | provide whatever clean-up operations might be required by preceding code. | ||||
130 | |||||
131 | Because it is executed during a stack cleanup operation, a C<finally {}> block | ||||
132 | may not cause the containing function to return, or to alter the return value | ||||
133 | of it. It also cannot see the containing function's C<@_> arguments array | ||||
134 | (though as it is block scoped within the function, it will continue to share | ||||
135 | any normal lexical variables declared up until that point). It is protected | ||||
136 | from disturbing the value of C<$@>. If the C<finally {}> block code throws an | ||||
137 | exception, this will be printed as a warning and discarded, leaving C<$@> | ||||
138 | containing the original exception, if one existed. | ||||
139 | =cut | ||||
140 | |||||
141 | sub import | ||||
142 | # spent 192µs (40+152) within Feature::Compat::Try::import which was called 6 times, avg 32µs/call:
# once (9µs+57µs) by OpenAPI::Modern::BEGIN@23 at line 23 of OpenAPI/Modern.pm
# once (13µs+46µs) by JSON::Schema::Modern::BEGIN@32 at line 32 of JSON/Schema/Modern.pm
# once (6µs+14µs) by JSON::Schema::Modern::Vocabulary::FormatAssertion::BEGIN@18 at line 18 of JSON/Schema/Modern/Vocabulary/FormatAssertion.pm
# once (4µs+13µs) by JSON::Schema::Modern::Vocabulary::FormatAnnotation::BEGIN@18 at line 18 of JSON/Schema/Modern/Vocabulary/FormatAnnotation.pm
# once (4µs+12µs) by JSON::Schema::Modern::Utilities::BEGIN@22 at line 22 of JSON/Schema/Modern/Utilities.pm
# once (4µs+10µs) by JSON::Schema::Modern::Vocabulary::Content::BEGIN@18 at line 18 of JSON/Schema/Modern/Vocabulary/Content.pm | ||||
143 | 6 | 25µs | if( HAVE_FEATURE_TRY ) { | ||
144 | 6 | 10µs | 6 | 71µs | feature->import(qw( try )); # spent 71µs making 6 calls to feature::import, avg 12µs/call |
145 | 6 | 2µs | require warnings; | ||
146 | 6 | 10µs | 6 | 81µs | warnings->unimport(qw( experimental::try )); # spent 81µs making 6 calls to warnings::unimport, avg 14µs/call |
147 | } | ||||
148 | else { | ||||
149 | require Syntax::Keyword::Try; | ||||
150 | Syntax::Keyword::Try->VERSION( '0.27' ); | ||||
151 | Syntax::Keyword::Try->import(qw( try -require_catch -require_var )); | ||||
152 | } | ||||
153 | } | ||||
154 | |||||
155 | =head1 COMPATIBILITY NOTES | ||||
156 | |||||
157 | This module may use either L<Syntax::Keyword::Try> or the perl core C<try> | ||||
158 | feature to implement its syntax. While the two behave very similarly, and both | ||||
159 | conform to the description given above, the following differences should be | ||||
160 | noted. | ||||
161 | |||||
162 | =over 4 | ||||
163 | |||||
164 | =item * Visibility to C<caller()> | ||||
165 | |||||
166 | The C<Syntax::Keyword::Try> module implements C<try> blocks by using C<eval> | ||||
167 | frames. As a result, they are visible to the C<caller()> function and hence to | ||||
168 | things like C<Carp::longmess> when viewed as stack traces. | ||||
169 | |||||
170 | By comparison, core's C<feature 'try'> creates a new kind of context stack | ||||
171 | entry that is ignored by C<caller()> and hence these blocks do not show up in | ||||
172 | stack traces. | ||||
173 | |||||
174 | This should not matter to most use-cases - e.g. even C<Carp::croak> will be | ||||
175 | fine here. But if you are using C<caller()> with calculated indexes to inspect | ||||
176 | the state of callers to your code and there may be C<try> frames in the way, | ||||
177 | you will need to somehow account for the difference in stack height. | ||||
178 | |||||
179 | =item * C<B::Deparse> | ||||
180 | |||||
181 | The core C<feature 'try'> is implemented by emitting real opcodes that | ||||
182 | represent its behaviour, which is recognised by the version of L<B::Deparse> | ||||
183 | that ships with core perl. As a result, any code using this implementation | ||||
184 | will deparse currently with tools like C<perl -MO=Deparse ...>, or others | ||||
185 | related to it such as coverage checkers. | ||||
186 | |||||
187 | By comparison, since C<Syntax::Keyword::Try> uses C<OP_CUSTOM> it is not | ||||
188 | recognised by C<B::Deparse> and so attempts to deparse this will result in | ||||
189 | error messages like | ||||
190 | |||||
191 | unexpected OP_CUSTOM (catch) at ... | ||||
192 | |||||
193 | This is rather unavoidable due to the way that C<B::Deparse> is implemented | ||||
194 | and does not easily support custom operators. | ||||
195 | |||||
196 | See also L<https://rt.cpan.org/Ticket/Display.html?id=134812>. | ||||
197 | |||||
198 | =back | ||||
199 | |||||
200 | =cut | ||||
201 | |||||
202 | =head1 AUTHOR | ||||
203 | |||||
204 | Paul Evans <leonerd@leonerd.org.uk> | ||||
205 | |||||
206 | =cut | ||||
207 | |||||
208 | 1 | 4µs | 0x55AA; |