I was looking at fixing an issue flagged by gometalinter, and realized I didn't understand the actual behavior of defer statements. Specifically, I was not handling the error return of a close operation.
I wrote a test program so I could understand the behavior, which led to these two function package main import "fmt" func checkDefer(newVal int, val *int) { fmt.Printf("current value is %v\n", *val) *val = newVal } func main() { fmt.Printf("variableOnUnnamedReturn value is %v, expected 30\n", variableOnUnnamedReturn(20, 25, 30)) fmt.Printf("variableOnNamedReturn value is %v, expected 45\n", variableOnNamedReturn(35, 40, 45)) } func variableOnUnnamedReturn(start, test, def int) int { retval := start defer checkDefer(def, &retval) retval = test return retval } func variableOnNamedReturn(start, test, def int) (retval int) { retval = start defer checkDefer(def, &retval) retval = test return retval } The body of the two functions differs only by a single ":", and yet, the output of the Printf calls differs. This appears to be due to very subtle differences between how named and unnamed returns are handled in the context of defer statements. I looked through the language spec, and did not see this clearly spelled out. It is not obvious to me, a relatively experience Go developer, that the "variableOnUnnamedReturn" function should return a 25 in the above use, but the "variableOnNamedReturn" function returns a 45 in the above use. As near as I can tell, operationally, the "unnamed" return could be re-written in something like the following fashion (where addDeferredOps is a collector for deferred operations.): retval := start dos := addDeferredOps(func() { checkDefer(def, &retval)} ) retval = test _retval1_ = retval dos.performDeferredOps() return _retval1_ Which makes it obvious that the call to checkDefer() won't change the return of the function. Whereas, the "named return" version effectively amounts to this: retval := start dos := addDeferredOps(func() { checkDefer(def, &retval)} ) retval = test dos.performDeferredOps() return retval I read the language spec, and simply didn't see the description of the difference between these two behaviors. Seems mostly like a language bug, to me. Feels like the named and unnamed return cases should behave the same. I can see why they don't (expressions on the return line, instead of simple uses of the variables), but that doesn't make me happy about having to explain the difference to others on my team. Eric. -- 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.