Show 143 quoted lines
> Try::Tiny is an increasingly standard part of Perl - for example, it's
> used extensively in Moose. There's a good list of arguments about why
> you should use it instead of eval in the Try::Tiny documentation:
> http://search.cpan.org/~nuffin/Try-Tiny-0.01/lib/Try/Tiny.pm
>
> Now I've got that talking point done, here's what I really think :)
>
> Try::Tiny is designed on the assumption that throwing and catching
> objects is something people should do all the time, and it can cause
> subtle errors that are only worth the hassle if you get a lot of benefit
> from doing so. It's easy enough to come up with ideas for where they
> might be useful, but in the real world advanced uses for exceptions are
> usually a sign you're doing it wrong. Three of the most common reasons
> for frequent/complex exceptions are handling errors further up the call
> stack, recovering from operations that fail, and clever error-handling.
>
>
> If you want exceptions to be caught by code further up the call stack
> than the immediate caller, you're likely to be disappointed. This is
> one of the places where "separation of concerns" applies - if I use a
> module that uses a module that uses your module, then catching
> exceptions from your code will just cause my program to break when some
> module in the middle obscures your error by adding its own layer of
> error handling.
>
>
> If you have an operation that really might fail, and you want to
> encourage most people to handle it most of the time, it's better to have
> a function with a meaningful name and good documentation. This puts the
> burden on the calling function to handle the error instead of letting
> them think "oh well, if it dies someone else will handle it". It also
> forces you to split functions along boundaries that make your code
> readable, instead of falling for the temptation to make something that
> "just works"... until it doesn't, and the maintainer has to go
> spelunking through code they don't know. So instead of:
>
> try {
> Foo::frobnicate( widgets => 3 );
> } catch {
> if (ref($_) eq 'Error::Widget') {
> die "Could not add 3 widgets";
> }
> }
>
> It's better to ask the people using your module to write:
>
> my $foo = Foo->new;
> $foo->add_widgets(3) or die "could not add 3 widgets"
> $foo->frobnicate;
>
> This is easier to document, easier to write and easier to read.
>
>
> If you have an operation where calling code is supposed to do something
> more complicated than give up, it's better to use a callback. This
> gives you an opportunity to document what's needed, and to check that
> the calling code is doing the right thing before it's too late. So
> instead of:
>
> my $widgets = 3;
> while ( $widgets ) {
>
> try {
> Foo::frobnicate($widgets);
> $widgets = 0;
> } catch {
> if ( $_->{remaining_widgets} < 2 ) {
> die $_->{error};
> } elsif ( $_->{remaining_widgets} == 2 ) {
> $widgets = 0;
> }
> }
>
> }
>
> It's better to ask people using your module to write:
>
> Foo::Frobnicate(
> widgets => 3,
> error_handler => sub {
> my ( $remaining_widgets, $error ) = @_;
> die $error if $broken_widgets < 2;
> return "give up" if $remaining_widgets == 2;
> return "continue";
> },
> );
>
> Again, this is more readable and easier to document.
>
>
> Aside from the philosophical angle, Try::Tiny is particularly hard to
> maintain because it looks like a language extension, but is actually
> just an ordinary module. The try {} and catch {} blocks are anonymous
> subroutines, which lead to some wonderfully unintuitive behaviour. See
> what you think these do, then run the code to find out:
>
>
> sub foo {
> try {
> return 1;
> }
> return 0;
> }
>
> sub bar {
>
> our @args = @_;
> our @ret;
>
> try {
> @ret =
> wantarray
> ? grep( /blah/, @args )
> : [ grep( /blah/, @args ) ]
> };
>
> return @ret;
> }
>
> my $foo = "bar";
> sub baz {
> my $foo = "baz";
> try {
> print $foo;
> }
> }
>
> sub qux {
> my $ret;
> try {
> $ret = "value";
> }
> return $ret;
> }
>
> print foo, "\n";
> print bar( "blah", "blip" ), "\n";
> baz;
> print qux, "\n";
>
>
> In short, Try::Tiny looks like a lot of gain for not much pain, but
> actually it's the other way around.