Commit | Line | Data |
3176feef |
1 | package Try::Tiny; |
2 | |
3 | use strict; |
ae53da51 |
4 | #use warnings; |
3176feef |
5 | |
ae53da51 |
6 | use vars qw(@EXPORT @EXPORT_OK $VERSION @ISA); |
7 | |
8 | BEGIN { |
9 | require Exporter; |
10 | @ISA = qw(Exporter); |
11 | } |
3176feef |
12 | |
13 | $VERSION = "0.01"; |
14 | |
15 | $VERSION = eval $VERSION; |
16 | |
17 | @EXPORT = @EXPORT_OK = qw(try catch); |
18 | |
19 | sub try (&;$) { |
20 | my ( $try, $catch ) = @_; |
21 | |
22 | # we need to save this here, the eval block will be in scalar context due |
23 | # to $failed |
24 | my $wantarray = wantarray; |
25 | |
26 | my ( @ret, $error, $failed ); |
27 | |
28 | # FIXME consider using local $SIG{__DIE__} to accumilate all errors. It's |
29 | # not perfect, but we could provide a list of additional errors for |
30 | # $catch->(); |
31 | |
32 | { |
33 | # localize $@ to prevent clobbering of previous value by a successful |
34 | # eval. |
35 | local $@; |
36 | |
37 | # failed will be true if the eval dies, because 1 will not be returned |
38 | # from the eval body |
39 | $failed = not eval { |
40 | |
41 | # evaluate the try block in the correct context |
42 | if ( $wantarray ) { |
43 | @ret = $try->(); |
44 | } elsif ( defined $wantarray ) { |
45 | $ret[0] = $try->(); |
46 | } else { |
47 | $try->(); |
48 | }; |
49 | |
50 | return 1; # properly set $fail to false |
51 | }; |
52 | |
53 | # copy $@ to $error, when we leave this scope local $@ will revert $@ |
54 | # back to its previous value |
55 | $error = $@; |
56 | } |
57 | |
58 | # at this point $failed contains a true value if the eval died even if some |
59 | # destructor overwrite $@ as the eval was unwinding. |
60 | if ( $failed ) { |
61 | # if we got an error, invoke the catch block. |
62 | if ( $catch ) { |
63 | # This works like given($error), but is backwards compatible and |
64 | # sets $_ in the dynamic scope for the body of C<$catch> |
65 | for ($error) { |
66 | return $catch->($error); |
67 | } |
44599111 |
68 | |
69 | # in case when() was used without an explicit return, the C<for> |
70 | # loop will be aborted and there's no useful return value |
3176feef |
71 | } |
44599111 |
72 | |
73 | return; |
3176feef |
74 | } else { |
75 | # no failure, $@ is back to what it was, everything is fine |
76 | return $wantarray ? @ret : $ret[0]; |
77 | } |
78 | } |
79 | |
80 | sub catch (&) { |
81 | return $_[0]; |
82 | } |
83 | |
84 | |
85 | __PACKAGE__ |
86 | |
87 | __END__ |
88 | |
89 | =pod |
90 | |
91 | =head1 NAME |
92 | |
93 | Try::Tiny - minimal try/catch with proper localization of $@ |
94 | |
95 | =head1 SYNOPSIS |
96 | |
97 | # handle errors with a catch handler |
98 | try { |
99 | die "foo"; |
100 | } catch { |
101 | warn "caught error: $_"; |
102 | }; |
103 | |
104 | # just silence errors |
105 | try { |
106 | die "foo"; |
107 | }; |
108 | |
109 | =head1 DESCRIPTION |
110 | |
111 | This module provides bare bones C<try>/C<catch> statements that are designed to |
112 | minimize common mistakes done with eval blocks (for instance assuming that |
113 | C<$@> is set to a true value on error, or clobbering previous values of C<$@>), |
114 | and NOTHING else. |
115 | |
116 | This is unlike L<TryCatch> which provides a nice syntax and avoids adding |
117 | another call stack layer, and supports calling C<return> from the try block to |
118 | return from the parent subroutine. These extra features come at a cost of a few |
119 | dependencies, namely L<Devel::Declare> and L<Scope::Upper> which are |
120 | occasionally problematic, and the additional catch filtering using L<Moose> |
121 | type constraints may not be desirable either. |
122 | |
123 | The main focus of this module is to provide reliable but simple error handling |
124 | for those having a hard time installing L<TryCatch>, but who still want to |
125 | write correct C<eval> blocks without 5 lines of boilerplate each time. |
126 | |
127 | It's designed to work as correctly as possible in light of the various |
128 | pathological edge cases (see L<BACKGROUND>) and to be compatible with any style |
129 | of error values (simple strings, references, objects, overloaded objects, etc). |
130 | |
131 | =head1 EXPORTS |
132 | |
133 | All are exported by default using L<Exporter>. |
134 | |
a717a876 |
135 | In the future L<Sub::Exporter> may be used to allow the keywords to be renamed, |
3176feef |
136 | but this technically does not satisfy Adam Kennedy's definition of "Tiny". |
137 | |
138 | =over 4 |
139 | |
140 | =item try &;$ |
141 | |
142 | Takes one mandatory and one optional catch subroutine. |
143 | |
144 | The mandatory subroutine is evaluated in the context of an C<eval> block. |
145 | |
a717a876 |
146 | If no error occurred the value from the first block is returned. |
3176feef |
147 | |
148 | If there was an error and the second subroutine was given it will be invoked |
149 | with the error in C<$_> (localized) and as that block's first and only |
150 | argument. |
151 | |
152 | Note that the error may be false |
153 | |
154 | =item catch & |
155 | |
a717a876 |
156 | Just returns the subroutine it was given. |
3176feef |
157 | |
158 | catch { ... } |
159 | |
160 | is the same as |
161 | |
162 | sub { ... } |
163 | |
164 | Intended to be used in the second argument position of C<try>. |
165 | |
166 | =back |
167 | |
168 | =head1 BACKGROUND |
169 | |
170 | There are a number of issues with C<eval>. |
171 | |
172 | =head2 Clobbering $@ |
173 | |
174 | When you run an eval block and it succeeds, C<$@> will be cleared, potentially |
a717a876 |
175 | clobbering an error that is currently being caught. |
3176feef |
176 | |
177 | C<$@> must be properly localized before invoking C<eval> in order to avoid this issue. |
178 | |
179 | =head2 Localizing $@ silently masks errors |
180 | |
181 | Inside an eval block C<die> behaves sort of like: |
182 | |
183 | sub die { |
184 | $@_ = $_[0]; |
185 | return_undef_from_eval(); |
186 | } |
187 | |
188 | This means that if you were polite and localized C<$@> you can't die in that |
189 | scope while propagating your error. |
190 | |
191 | The workaround is very ugly: |
192 | |
193 | my $error = do { |
194 | local $@; |
195 | eval { ... }; |
196 | $@; |
197 | }; |
198 | |
199 | ... |
200 | die $error; |
201 | |
202 | =head2 $@ might not be a true value |
203 | |
204 | This code is wrong: |
205 | |
206 | if ( $@ ) { |
207 | ... |
208 | } |
209 | |
210 | because due to the previous caveats it may have been unset. $@ could also an |
211 | overloaded error object that evaluates to false, but that's asking for trouble |
212 | anyway. |
213 | |
214 | The classic failure mode is: |
215 | |
216 | sub Object::DESTROY { |
217 | eval { ... } |
218 | } |
219 | |
220 | eval { |
221 | my $obj = Object->new; |
222 | |
223 | die "foo"; |
224 | }; |
225 | |
226 | if ( $@ ) { |
227 | |
228 | } |
229 | |
230 | In this case since C<Object::DESTROY> is not localizing C<$@> but using eval it |
231 | will set C<$@> to C<"">. |
232 | |
233 | The destructor is only fired after C<die> sets C<$@> to |
234 | C<"foo at Foo.pm line 42\n">, so by the time C<if ( $@ )> is evaluated it has |
235 | become false. |
236 | |
237 | The workaround for this is even uglier. Even though we can't save the value of |
238 | C<$@> from code that doesn't localize it but uses C<eval> in destructors, we |
239 | can at least be sure there was an error: |
240 | |
241 | my $failed = not eval { |
242 | ... |
243 | |
244 | return 1; |
245 | }; |
246 | |
247 | This is because an C<eval> that caught a C<die> will always behave like |
248 | C<return> with no arguments. |
249 | |
f9b91e2c |
250 | =head1 SHINY SYNTAX |
3176feef |
251 | |
252 | Using Perl 5.10 you can enable the C<given>/C<when> construct. The C<catch> |
253 | block is invoked in a topicalizer context (like a C<given> block). |
254 | |
255 | Note that you can't return a useful value from C<catch> using the C<when> |
27293e40 |
256 | blocks without an explicit C<return>. |
3176feef |
257 | |
258 | This is somewhat similar to Perl 6's C<CATCH> blocks. You can use it to |
259 | concisely match errors: |
260 | |
261 | try { |
262 | require Foo; |
263 | } catch { |
264 | when (qr/^Can't locate .*?\.pm in \@INC/) { } # ignore |
265 | default { die $_ } |
266 | } |
267 | |
268 | =head1 CAVEATS |
269 | |
270 | =over 4 |
271 | |
272 | =item * |
273 | |
274 | Introduces another caller stack frame. L<Sub::Uplevel> is not used. L<Carp> |
275 | will report this when using full stack traces. This is considered a feature. |
276 | |
277 | =item * |
278 | |
279 | The value of C<$_> in the C<catch> block is not guaranteed to be preserved, |
280 | there is no safe way to ensure this if C<eval> is used unhygenically in |
281 | destructors. It is guaranteed that C<catch> will be called, though. |
282 | |
283 | =back |
284 | |
285 | =head1 SEE ALSO |
286 | |
287 | =over 4 |
288 | |
289 | =item L<TryCatch> |
290 | |
291 | Much more feature complete, more convenient semantics, but at the cost of |
292 | implementation complexity. |
293 | |
f8227e43 |
294 | =item L<Throwable> |
295 | |
296 | A lightweight role for rolling your own exception classes. |
297 | |
3176feef |
298 | =item L<Error> |
299 | |
300 | Exception object implementation with a C<try> statement. Does not localize |
301 | C<$@>. |
302 | |
303 | =item L<Exception::Class::TryCatch> |
304 | |
305 | Provides a C<catch> statement, but properly calling C<eval> is your |
306 | responsibility. |
307 | |
308 | The C<try> keyword pushes C<$@> onto an error stack, avoiding some of the |
309 | issues with C<$@> but you still need to localize to prevent clobbering. |
310 | |
311 | =back |
312 | |
313 | =head1 VERSION CONTROL |
314 | |
315 | L<http://github.com/nothingmuch/try-tiny/> |
316 | |
317 | =head1 AUTHOR |
318 | |
319 | Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt> |
320 | |
321 | =head1 COPYRIGHT |
322 | |
c4e1eb12 |
323 | Copyright (c) 2009 Yuval Kogman. All rights reserved. |
3176feef |
324 | This program is free software; you can redistribute |
c4e1eb12 |
325 | it and/or modify it under the terms of the MIT license. |
3176feef |
326 | |
327 | =cut |
328 | |