-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/compile: named return values produce functionally different code #21049
Comments
The example given was derived from some error logging/reporting code. Here is an example that uses primitives ( On the playground, it prints:
|
This is working as intended. These are actually different. In your Foo func, the return statement is modifying the named return value before it returns, per the spec: https://golang.org/ref/spec#Return_statements
|
@bradfitz Both |
The only difference between |
No, that's not true. They really are different The The Think of your func Bar() (err error) {
var otherErr error
otherErr = errors.New("Bar error")
defer ModifyErr(&otherErr)
err = otherErr // runs before ModifyErr
return
} Again, this is all per the language spec I linked above. See also the scope sections. |
@bradfitz Thanks. That example helped. I expected it had something to do with the scoping of the named return parameter. I didn't see that in the |
I think you guys are missing the point---if you forget to name the return result, you get different results. That is, a "fat finger" typo can produce in subtle bugs. Incidentally, it also very easy to overlook in a code review. Are there any automated tooling that can come to the rescue? |
@frankandrobot It's true that this is something one needs to learn about Go, but I don't think it is any more subtle than other aspects of the language. The odd thing is naming a result parameter: when you name a result parameter, you have to consider any references to that result parameter in deferred functions. That is one of the major uses of named result parameters: being able to change them in a deferred function. |
It's not a matter of learning @ianlancetaylor---the concept of named return vars can be grokked in a few minutes. It's a matter of doing. Forgetting to name the return variable is very easy to do, very easy to overlook in a code review, yet can produce subtle bugs. |
I would say that forgetting to name the result variable is the normal case. I understand you to be saying is that if you want to do something fancy--to use a deferred function to change the result--then it is possible to accidentally refer to a local variable rather than to a named result variable. That is true. But I don't see that as any more subtle than any other sort of variable shadowing. |
Perhaps in this use case, "use a deferred function to change the result", there is an alternative pattern? Incidentally, the real use case is committing a database transaction and then ensuring any errors get propagated. |
This might be a duplicate of #20859. Filing it separately because the discussion in #20859 is mostly about code-generation, not functional differences.
What version of Go are you using (
go version
)?What operating system and processor architecture are you using (
go env
)?What did you do?
https://play.golang.org/p/Ig-Jnvz07B
What did you expect to see?
The same behavior from both
Foo
andBar
; probablyBar
is correct.What did you see instead?
This code produces:
The text was updated successfully, but these errors were encountered: