Try::Tiny rocks.
Every perl programmer should start using it. Especially if you're a CPAN module author and wants to eval { } inside your module (often to check if an user of your module has some optional module installed, in which case you optimize stuff for it etc.), you're strongly suggested to use this module instead of your own eval { } stuff.
Why? If you do eval { } in your module that clobbers the global $@, and to avoid that you need to local $@, and then if you want to die (rethrow) from local $@ then the exception gets cleared etc... Try::Tiny solves this endless yak shaving and there're no dependencies at all and works with perl back to 5.005x.
Anyway, i started using Try::Tiny (when nothingmuch himself added this :)) in Plack and Tatsumaki with so much fun, but last night I experienced one minor pitfall of this module that I might want to share with you.
I had this code:
sub write {
my $self = shift;
my $writer = $self->writer || $self->init_writer;
$writer->write(@_);
}
I wanted to catch Broken pipe exception from ->write, so I changed to do this:
sub write {
my $self = shift;
my $writer = $self->writer || $self->init_writer;
try {
$writer->write(@_);
} catch {
/Broken pipe/ and $self->{client_disconnected} = 1;
};
}
It might be obvious to you but for me it wasn't at first, and I wasted about 15 minutes to figure out what's wrong with that code.
Yeah, the use of @_ in the try { } clause. it's internally implemented as try sub { ... } so the content of @_ is changed when it's executed.
Lots of clever modules on CPAN that exports DSL sugars (including my own Web::Scraper) shares the same problem. At least you have to be careful not to use @_ in the block, by assigning the @_ content into some lexical variables before you construct the block,
(Well maybe Try::Tiny can add a workaround to save the @_ in the caller stack but i'm not sure if it's a doable without black magic like DB::args and whether it's right thing to do anyway)
Anyways, Try::Tiny is a great module if you care about this tiny thing. Enjoy.
UPDATE: this is now mentioned in Try::Tiny POD docs.





Try::Tiny was written to fill the void between cargo culting your own eval { } stuff, and using TryCatch.
Basically if you have some excuse to not use TryCatch (like an irrational fear or a need to trim dependencies), you still have no excuse for a broken use of eval ;-)
Posted by: Yuval | 2009.10.20 at 14:26
Very cool! I think I might rewrite my IRC client (streams JSON over HTTP) to use Tatsumaki. It looks like it handles a lot of the annoying issues I ran into using PoCo::HTTP::Server.
Posted by: Lee Aylward | 2009.10.20 at 15:52
Ha, cool! Remember, Tatsumaki is (yet) my toy and APIs and stuff will be changed a lot, at least until it hits CPAN sometime in the future :) For now feel free to toy with the code on my git repo :)
Posted by: miyagawa | 2009.10.20 at 15:55
TryCatch rocks more!
With TryCatch you would not run into this problem. And another important thing. You can return() in the try block or have multiple catch blocks to catch for error classes.
Like Yuval said. If you don't have a reason against TryCatch you should use this instead of Try::Tiny.
Posted by: Sid Burn | 2009.10.21 at 00:59
Yes, I know.
As I mentioned in the post, I mostly suggest CPAN authors to consider using Try::Tiny since it's MUCH better than doing local $@; eval { } if $@ in their code and there's no dependencies at all and works with perl back to 5.5.
Using TryCatch in your, say, List::Compare module is so silly considering its dependencies, most of which are even XS and requires C compilers.
Posted by: miyagawa | 2009.10.21 at 01:05
Try::Tiny++
It would be nice if a workaround for Stacktraces were documented in the doc.
(Next to where it says that Sub::Uplevel not being used is a feature)
Posted by: Yann | 2009.10.29 at 15:57
Does Try::Tiny work with Class::Exception?
I'm using both and find that $_ isn't being set.
Posted by: Bob the builder | 2009.12.08 at 07:14
I don't know, but Try::Tiny shouldn't do anything special whether an exception is an object or not, so $_ should be set to whatever object it's thrown.
Posted by: miyagawa | 2009.12.08 at 07:31