On 10 May 2012 22:55, Andrew Sayers <andrew-git@xxxxxxxxxxxxxxx> wrote: > 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. Total agreement. Yves -- perl -Mre=debug -e "/just|another|perl|hacker/" -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html