doy / try-tiny

minimal try/catch with proper preservation of $@
http://metacpan.org/release/Try-Tiny
10 stars 15 forks source link

try, try_again and $TRIES #20

Closed pilcrow closed 10 years ago

pilcrow commented 10 years ago

This change implements, tests, and documents the optionally exported try_again() (restart the try{} without running finally{}) and $TRIES (how many times has this try{} block been invoked?).

Use case

I often want to do simple retries of try{} catch{} finally {} stanzas, but need to keep track of the number of tries myself, and have to go through some contortions if I want finally{} clauses to run only when I have given up trying. Try::Tiny::Retry is too much / too stilted for my simple uses, but I am lazy and tired of doing all that bookkeeping myself.

Now I can say:

use Try::Tiny qw(:DEFAULT try_again $TRIES);

try { ... }
catch { try_again if $TRIES < $my_patience; }  # BTW, $TRIES is correct for nested uses, too!
finally { ... }

Implementation

The main work of try(&;@) now contains a labelled block, and try_again simply does a goto. catch blocks are run from a special function so that try_again can look for that function in the call stack and not goto willy nilly. Finally, finally scope guards are created only after the first try{}.

$TRIES is a simple tied scalar that tracks the (localized) number of passes through the labelled block.

Testing

Tests are added for proper symbol exporting, for misuse of try_again, and for retries of nested try{} stanzas.

Your existing test suite is excellent and unaltered, by the way.

Documentation

POD is updated for new functionality, and a reference to Try::Tiny::Retry is added.

doy commented 10 years ago

This is unlikely to be merged. One of the primary goals of Try::Tiny is to be as simple as possible in order to also serve as a source of documentation for the correct way to handle exceptions in Perl (see the first paragraph of the DESCRIPTION section in the documentation). This sort of extra behavior belongs in an external module that uses Try::Tiny underneath - if Try::Tiny::Retry doesn't suit your needs, you could certainly write another one that does.

pilcrow commented 10 years ago

Well, this change struck me as in-scope for common exception handling — how do I correctly retry a block after an exception? — and as not supported by Try::Tiny now. (You can't simply wrap the whole stanza in a loop, nor goto a RETRY: try {...}, since your finally{} clauses will run. Bummer. That's not correct exception handling.)

But it was worth a shot. I understand if this feels more like Try::Lite than Try::Tiny.