refactor the case of abortive when()
[p5sagit/Try-Tiny.git] / lib / Try / Tiny.pm
1 package Try::Tiny;
2
3 use strict;
4 #use warnings;
5
6 use vars qw(@EXPORT @EXPORT_OK $VERSION @ISA);
7
8 BEGIN {
9         require Exporter;
10         @ISA = qw(Exporter);
11 }
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                         }
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
71                 }
72
73                 return;
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
135 In the future L<Sub::ExporteR> may be used to allow the keywords to be renamed,
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
146 If no error occured the value from the first block is returned.
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
156 Just retuns the subroutine it was given.
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
175 cloberring an error that is currently being caught.
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
250 =head1 SHINY SUGAR
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>
256 blocks without an explicit C<return>.
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
294 =item L<Error>
295
296 Exception object implementation with a C<try> statement. Does not localize
297 C<$@>.
298
299 =item L<Exception::Class::TryCatch>
300
301 Provides a C<catch> statement, but properly calling C<eval> is your
302 responsibility.
303
304 The C<try> keyword pushes C<$@> onto an error stack, avoiding some of the
305 issues with C<$@> but you still need to localize to prevent clobbering.
306
307 =back
308
309 =head1 VERSION CONTROL
310
311 L<http://github.com/nothingmuch/try-tiny/>
312
313 =head1 AUTHOR
314
315 Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt>
316
317 =head1 COPYRIGHT
318
319     Copyright (c) 2009 Yuval Kogman. All rights reserved.
320         This program is free software; you can redistribute
321     it and/or modify it under the terms of the MIT license.
322
323 =cut
324