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