Neat. What you and I are doing is very similar. Particularly how the 
handler is "bound" to the error and checks to make sure that the error is 
non-nil before attempting to recover.

The differences I see in our approaches are as follows:


I support wrapping an error or performing some arbitrary action. This 
wouldn't be difficult for you to add - just add a func() parameter to 
RecoverOn that is invoked when *err != nil. If you did that then we would 
both support performing actions whether an early return was triggered by 
check/ro.ReturnOn or a regular return with err set (assuming named return 
values).


I bind the check function (what you call ro.ReturnOn) to the error so that 
it can set that when passed a non-nil error. This allows check to be used 
directly, for example, on a function that only returns an error:

check(functionThatReturnsAnError())

Instead of having to do:

err = functionThatReturnsAnError()
ro.ReturnOn(err)

Binding the check and done functions means returning them both from a call 
to handle.Error. This adds one more line of code (defer done()) but means 
that check doesn't exist without this step and given that Go complains 
about unused variables it takes some work to forget to do something with 
done. My hope is that this significantly reduces the risk of an unhandled 
panic. (It's still possible to just call done and forget to defer it or 
name done _ so that the compiler won't complain, etc., etc.) As an added 
bonus people can call this pair of functions whatever they want 
(check/done, try/handle, ReturnOn/RecoverOn...). When I first posted I 
thought it would be neat to do:

check, handle := handle.Error // ...
so that the shadowing would make it impossible to call handle.Error again. 
But then I added Chain.

(It would be nice to get the handle.Errorf case down to one line but I 
haven't figured out a way to do that. Maybe something with how arguments to 
deferred function are evaluated but the function call itself isn't...)


In check I wrap the error in an unexported type:

type failure struct {
error
}

If this manages to slip by the idea is that it should be reported as an 
"unhandled error" plus the text of the actual error. It is the 
responsibility of done to unwrap the error and perform any actions on that. 
I'm paranoid about invoking recover, only invoke it when the error is the 
unexported failure type and even then check to make sure that the recovered 
value matches the error value. It is possible to always recover and then if 
we recover something we weren't supposed to, re-panic, but then we lose all 
the context for the original panic.


Looking back at the error handling problem outline I realized that I did 
not have the ability to add additional error handling actions. I added 
Chain a few days after my original post.


Michael.

On Saturday, February 20, 2021 at 4:21:10 PM UTC-5 michael...@gmail.com 
wrote:

> FWIW,  I've put together a tiny package that, with some tradeoffs, seems 
> useful for reducing boilerplate in the common case where a function simply 
> wants to return an error to its caller.  
>
> https://github.com/Michael-F-Ellis/ro
>
> The code is almost trivial. It consists of two small functions, 
> ro.RecoverOn( err *error) and ro.ReturnOn(err error), used as follows:
>
> import "github.com/Michael-F-Ellis/ro" 
>
> func myfunc() (err error) { 
>     defer ro.RecoverOn(&err) 
>
>     err = SomeFunctionCall() 
>     ro.ReturnOn(err)
>
>     // Do more stuff 
>     // ... 
>     return 
> }
>
> ReturnOn panics if err is not nil.
>
> RecoverOn recovers from the panic raised by ReturnOn and the function 
> exits with whatever error value would have been returned 
> normally. RecoverOn does not interfere with panics arising outside 
> of ReturnOn.
>
> Benefits and tradeoffs (coding discipline, debugging, performance) are 
> discussed in the README.
>
> Feedback welcomed either in this thread or in the repo issues.
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/87c73aa0-2ea2-4125-8cc9-3fe7972a4db9n%40googlegroups.com.

Reply via email to