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.

Reply via email to