| 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 | Feature::Compat::Try::BEGIN@13 |
| 6 | 6 | 6 | 40µs | 192µs | Feature::Compat::Try::import |
| 1 | 1 | 1 | 33µs | 33µs | Feature::Compat::Try::BEGIN@8 |
| 1 | 1 | 1 | 10µs | 65µs | Feature::Compat::Try::BEGIN@9 |
| 1 | 1 | 1 | 6µs | 6µs | Feature::Compat::Try::BEGIN@10 |
| 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; |