Skip Menu |

This queue is for tickets about the future CPAN distribution.

Report information
The Basics
Id: 84118
Status: resolved
Priority: 0/
Queue: future

People
Owner: Nobody in particular
Requestors: TOSHIOITO [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.11
Fixed in: (no value)



Subject: I really beg you to take back the exception catching feature in Future 0.11
I really beg you to take back the new feature in Future 0.11, in which exceptions are caught by Future in followed_by(), and_then() and or_else() callbacks. This is because it can unintensionally hide critical errors and lead to hard-to-solve bugs. Suppose I use a function from someone's module. package Someones::Module; sub bad_func { die __PACKAGE__ . ": something bad happened."; } It is often the case that a function throws an exception in some cases. And sometimes it is NOT EVEN DOCUMENTED. Then, when I use it in Future's callback, package main; my $start = Future->new; $start->and_then(sub { my ($arg) = shift->get; my $result = Someones::Module::bad_func($arg); print "We get the result: $result"; return Future->new->done($result); }); $start->done('a'); with Future 0.11, the above code prints nothing. If I didn't read Future's documentation from page to page, I would have no idea what's going on. The thrown exception lives in the sense that it makes the resulting future fail. However, the failed future can be easily ignored unless the user has explicit intension to check errors. I believe errors as important as exceptions must be visible regardless of the user's intension or carefulness. Therefore, I really beg you to take back the exception catching feature in Future 0.11.
On Thu Mar 21 08:36:07 2013, TOSHIOITO wrote: Show quoted text
> Then, when I use it in Future's callback, > > package main; > my $start = Future->new; > $start->and_then(sub { > my ($arg) = shift->get; > my $result = Someones::Module::bad_func($arg); > print "We get the result: $result"; > return Future->new->done($result); > }); > $start->done('a'); > > with Future 0.11, the above code prints nothing. If I didn't read > Future's documentation from page to page, I would have no idea what's > going on.
I would say the trouble here is that you are using ->and_then, which returns a Future, but calling it in void context and ignoring the Future it yields. If you wanted to do that, you in fact want to use the ->on_done method to attach a callback, because that version specifically /does not/ catch exceptions for this exact reason. Your code should read: my $start = Future->new; $start->on_done(sub { my $arg = shift; my $result = Someones::Module::bad_func($arg); print "We get the result: $result"; }); $start->done('a'); Now, if the bad_func() throws an exception, this will not be caught and the exception will be propagated through to the $start->done() call. Show quoted text
> The thrown exception lives in the sense that it makes the resulting > future fail. However, the failed future can be easily ignored unless > the user has explicit intension to check errors. I believe errors as > important as exceptions must be visible regardless of the user's > intension or carefulness. > > Therefore, I really beg you to take back the exception catching > feature in Future 0.11.
How about instead making the methods that return a Future give a warning if called in void context; which means that the Future would be ignored, including any failures that might come from it. That feels like it would also catch a bigger class of error that way. Would that work better for you? -- Paul Evans
On Thu Mar 21 09:23:24 2013, PEVANS wrote: Show quoted text
> How about instead making the methods that return a Future give a > warning if called in void context; which means that the Future > would be ignored, including any failures that might come from it. > That feels like it would also catch a bigger class of error that > way.
I guess also this point could be clearer made in the docs, and pointing out that and_then/etc.. all catch exceptions; and that the on_done version doesn't. -- Paul Evans
I see your point. So the best practice is, (1) always call on_{ready,done,fail} methods on leaf Futures, (2) don't ignore Futures. However, checking void context is not enough to detect whether the Future is ignored. I suppose it's better to use DESTROY method just like PERL_FUTURE_DEBUG option does. I suggest when a failed Future is DESTROYed, it throw an exception if the failure is not "handled". We can determine whether a Future has been handled or not by keeping track of method calls on it. I think the above strategy is a good idea. If you are OK, I will try to implement it as a subclass module (like Future::Strict or something) On 2013-3月-21 木 09:25:21, PEVANS wrote: Show quoted text
> On Thu Mar 21 09:23:24 2013, PEVANS wrote: >
> > How about instead making the methods that return a Future give a > > warning if called in void context; which means that the Future > > would be ignored, including any failures that might come from it. > > That feels like it would also catch a bigger class of error that > > way.
> > I guess also this point could be clearer made in the docs, and > pointing out that and_then/etc.. all catch exceptions; and that the > on_done version doesn't.
On Fri Mar 22 07:14:46 2013, TOSHIOITO wrote: Show quoted text
> I see your point. So the best practice is, (1) always call > on_{ready,done,fail} methods on leaf Futures, (2) don't ignore > Futures.
If you're not expecting to return another Future and use the returned Future from ->and_then/etc.. then yes. Show quoted text
> However, checking void context is not enough to detect whether the > Future is ignored.
It's not an infallible solution but it should help quite a few of the common errors. It is of course still possible to save the Future to a variable then not do anything with it. Show quoted text
> I suppose it's better to use DESTROY method just > like PERL_FUTURE_DEBUG option does.
Show quoted text
> I suggest when a failed Future is DESTROYed, it throw an exception if > the failure is not "handled". We can determine whether a Future has > been handled or not by keeping track of method calls on it.
Yes; that might be a useful idea. Since we're now catching exceptions and turning them into Future failures, we should probably alert to the fact that a Future was dropped with nothing handling its failure. It should be careful though not to alert on the fact that a successful Future was dropped - it may be the case that the Future was executed simply for a side-effect of some kind, and losing its return value may not be a problem. Show quoted text
> I think the above strategy is a good idea. If you are OK, I will try > to implement it as a subclass module (like Future::Strict or something)
Hmm.. A ::Strict subclass sounds interesting, yes. Have a go at implementing that, but if it looks sufficiently useful it may be worth just putting that in the base Future class itself. Offhand I can't think of a great reason why not, but there may be complications as yet unforeseen. -- Paul Evans
Show quoted text
> It should be careful though not to alert on the fact that a successful > Future was dropped
Thank you for the advice. Yes, it is no problem to ignore successful Futures. Show quoted text
> Offhand I > can't think of a great reason why not, but there may be > complications as yet unforeseen.
I agree. So the "strict" Future should be optional, even if it is incorporated into the base Future class. I started writing Future::Strict at Github. https://github.com/debug-ito/Future-Strict The implementation is not gonna be complicated, I guess, but it may take some time for me to write enough test cases. Since my problem will be solved with Future::Strict, I closed this ticket. Thank you for the valuable discussion.