I'd think, the spec is reasonably unambiguous, if not very explicit. The second version works, because of
For instance, if the deferred function is a function literal and the > surrounding function has named result parameters that are in scope within > the literal, the deferred function may access and modify the result > parameters before they are returned. and The recover function allows a program to manage behavior of a panicking > goroutine. Suppose a function G defers a function D that calls recover and > a panic occurs in a function on the same goroutine in which G is executing. > When the running of deferred functions reaches D, the return value of D's > call to recover will be the value passed to the call of panic. If D returns > normally, without starting a new panic, the panicking sequence stops. In > that case, the state of functions called between G and the call to panic is > discarded, and normal execution resumes. Any functions deferred by G before > D are then run and G's execution terminates by returning to its caller. i.e. after recover(), the execution continues as normally and the normal behavior is, that you can modify named return parameters and the modified version will then be returned. The first version also works as expected: recover() resumes execution as normal and you can modify result and error as wished, but they are just variables, not return values. Thus the function returns with the return parameters unset (as you panic'ed before setting them with return). If it helps, you can imagine the return values as variables, initialized to their zero values, which can be set in two ways: Either by having a return or by naming them, which gives you direct access. A panic won't modify them, but a defer'ed function might, if they are named. In your first version, you never set them; return isn't called and they are not named. In the second version you do set them; return isn't called, but you name them and set them from the defer'ed function. Maybe the confusion is about what "after the surrounding function returns" means? Maybe you interpret that as basically a "goto the line of the return statement and execute it", whereas the spec means it as "executing the function epilogue and return control to the caller"? The goto-like interpretation doesn't make sense, in any case; there could be multiple, pairwise contradictory return statements and it wouldn't be clear which is executed. FWIW I do believe the spec could be clearer here. The behavior seems logical and expected to me, but I do have trouble justifying this intuition with the spec. On Fri, Aug 26, 2016 at 9:11 AM, dc0d <kaveh.shahbaz...@gmail.com> wrote: > There deferred function here has not any return value - to get discarded. > It rather assigns a value to the *closure* *err* variable. > > Since a defer statement "*invokes a function whose execution is deferred > to the moment the surrounding function returns*", so I expected the *err* > variable should have a value just before the return statement executes. > > The *err* variable is just a closure. Still I'm confused why the first > version does not behave as expected - because the actual function *is not > invoked yet* at the position of defer statement but just it's parameters. > "*Instead, deferred functions are invoked immediately before the > surrounding function returns*". > > Why this is not behaving as expected? > > > On Friday, August 26, 2016 at 3:25:11 AM UTC+4:30, Vasko Zdravevski wrote: >> >> I put your code snippet in the playground for easier sharing: >> https://play.golang.org/p/ZvuNwjS7ZF >> >> I think the spec has the answer you're looking for regarding how named >> result parameters are handled during a panic. >> https://golang.org/ref/spec#Defer_statements >> >> Specifically the sentence: >> >>> If the deferred function has any return values, they are discarded when >>> the function completes. (See also the section on handling panics >>> <https://golang.org/ref/spec#Handling_panics>.) >>> >> >> Also, >> >>> If the function's signature <https://golang.org/ref/spec#Function_types> >>> declares result parameters, the function body's statement list must >>> end in a terminating statement >>> <https://golang.org/ref/spec#Terminating_statements>. >>> >> https://golang.org/ref/spec#Function_declarations >> >> And the panic is the 'terminating statement' >> >> Hope this helps, >> Vasko. >> >> On Thursday, August 25, 2016 at 4:19:17 PM UTC-6, dc0d wrote: >>> >>> Assuming we have this test: >>> >>> func TestRecover(t *testing.T) { >>> f := func() (interface{}, error) { >>> panic(`TEST`) >>> } >>> r, e := Recover(f) >>> t.Log(r, e) >>> } >>> >>> And two versions of *Recover* function. >>> >>> Version 1: >>> func Recover(f func() (interface{}, error)) (interface{}, error) { >>> var result interface{} >>> var err error >>> >>> defer func() { >>> if e := recover(); e != nil { >>> err = errors.Error(fmt.Sprintf("%v", e)) >>> } >>> }() >>> >>> result, err = f() >>> >>> return result, err >>> } >>> >>> >>> Version 2: >>> func Recover(f func() (interface{}, error)) (res interface{}, err error) >>> { >>> defer func() { >>> if e := recover(); e != nil { >>> err = errors.Error(fmt.Sprintf("%v", e)) >>> } >>> }() >>> >>> res, err = f() >>> >>> return res, err >>> } >>> >>> >>> *Question:* Why the output of test for Version 1 is *<nil> <nil>* (*not >>> expected/wrong*) but for Version 2 is *<nil> TEST* (*as >>> expected/correct*)? >>> >>> - Go 1.7, Ubuntu 14.04 x64 >>> >> -- > 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. > For more options, visit https://groups.google.com/d/optout. > -- 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. For more options, visit https://groups.google.com/d/optout.