-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
proposal: Go 2: remove bare return #21291
Comments
I would be against this change, for a few reasons.
|
Simplicity beats verbosity. A bunch of |
This comment was marked as resolved.
This comment was marked as resolved.
I don't think this func oops() (string, *int, string, error) {
...
return "", nil, "", &SomeError{err}
} is more readable than func oops() (rs1 string, ri *int, rs2 string, e error) {
...
e = &SomeError{err}
return
} ,sorry. |
OTOH - yes, shadowing sucks. It would not make sense to outlaw it outright (generated code comes to mind), but I would gladly vote for at least prohibition of return values names shadowing. Oh, and make compiler generate some diagnostic in all other cases would be nice too :) Edit: apparently there is #377 that talks about it |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
A func without return values should still be able to "bare" func noReturn() {
if !someCondition() {
return // bail out
}
// Happy path
} |
I spent 1.5 minutes looking at the following Go code in Go standard library (from 4 years ago, /cc @bradfitz), in disbelief, thinking there might be a bad bug: Lines 3158 to 3166 in 2d69e9e
Specifically, this part: tc, err := ln.AcceptTCP()
if err != nil {
return
} At first glance, it looked to me that on the first line there, new variables After about 90 seconds of thinking very hard about it, I realized that it's actually correct code. Since the named (Had it been in a new block, it would actually be a compile error "err is shadowed during return", see here.) I think this would've been much more clear and readable code: tc, err := ln.AcceptTCP()
if err != nil {
return nil, err
} I wanted to share this story because I think it's a good example of bare returns wasting programmer time. In my opinion, bare returns are marginally easier to write (just saving a few keystrokes), but often lead to code that's harder to read compared to equivalent code that uses full returns (non-bare). Go usually does the right thing of optimizing for reading, since that's done much more often (by more people) than writing. It seems to me that the bare returns feature tends to lower readability, so it might be the case that removing it in Go 2 would make the language better. Disclaimer: In Go code I write and read most often, I tend to avoid having bare returns (because I think they're less readable). But that means I have less experience reading/understanding bare returns, which might negatively influence my ability to read/parse them. It's a bit of catch-22. |
@shurcooL, interesting example that threw me off as well. For me it was the fact that there're two connection variables |
This is probably relevant: https://blog.minio.io/golang-internals-part-2-nice-benefits-of-named-return-values-1e95305c8687 And the associated discussion: |
From the article:
Named return values are great! Bare return of named return values are the problem. :-) |
@awnumar, that is not relevant. See my comment on Hacker News: https://news.ycombinator.com/item?id=14668595 |
I think removing these would follow the approach of explicit error handling. I don’t use them. Code I’ve reviewed on golang-nuts with bare returns isn’t difficult to understand, but parsing variable scope is an unnecessary added effort for readers. |
I really love bared return, especially when a function has multiple returns. It’s just making the code much cleaner. The biggest reason, I chose to work with go. Go tool vet shadow can detect potential shadowed vars. If a func has less cyclomatic complexity, plus some test cases. I couldn’t see it will get any trouble. I could be wrong, but I wish to see some examples to demonstrate how bad bared return could be. |
@kelwang Did you see my example about |
Hi, @shurcooL, thx Yeah, I think you made a great point. I think it's not really an issue for bared return. But a confusion in multiple vars initialization. For me, the shadow vet tool usually works very well. I never really worry about that. |
@kelwang In my opinion, if a function has multiple returns to the point where the return statements are getting ugly, a struct/pointer to a struct should be returned instead over a bare return. |
Since #377 has been mentioned, I would argue that the source of confusion in the I think the func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
:tc, err = ln.AcceptTCP()
if err != nil {
return
}
// ...
} By just looking at a multi-variable I've seen many proposal trying to address specific consequences of this, but I think the root of the problem is just the lack of explicitness of I'm not saying that bare returns are necessarily worth it, I'm just saying that what we are seeing is a compound problem. |
Regardless of the readability arguments, I think the bare return is less logically consistent and elegant. It's somehow a shaky standpoint. Although, obviously I'm not the only one being subjective here. |
@tandr I think returning a small struct object is much more clear than having more than three return values. |
I agree with you on that. It makes me pause to try to figure out what values are assigned to the named parameter variables. My discomfort reading (especially long) functions with naked returns is that I can't follow easily what are actually returned. Each naked return actually means When writers write in naked returns, they tend not to think about what are returned. When I asked them to avoid naked returns, now they think about the actual value they want to return and notice that they were returning wrong values like partially constructed values. Isn't being explicit better than implicit? I know it's recommended to indent error flows but not everyone follows this pattern in reality, especially folks who like to write long functions with lots of naked returns. Sometimes, it's hard to know if it's in an error flow or not by looking many naked returns. I read the code carefully decode it and convert naked returns to non-naked with some literal values, then it's much easier to read. (sometimes it's not possible to figure out the literal values if the code is complex) I know the documentation comment block mentions what it returns for some meaningful conditions, but not everyone does that. With return statement with some literal values, I can follow that easily by looking at the code. I know we can use named parameters and non-naked returns together, but not everyone knows that. I often see something like the following, and I think
I disagree on the other proposal that It's possible that lint tools can check it ( Go is very clear and readable language in my opinion. And naked return is a small part of the language that makes me hard to understand the code. |
Change https://golang.org/cl/189778 mentions this issue: |
The signature of parseMetaGoImports implies that it can return an error, but it has not done so since CL 119675. Restore the missing error check, and remove the named return-values to avoid reintroducing this bug in the future. Updates #30748 Updates #21291 Change-Id: Iab19ade5b1c23c282f3c385a55ed277465526515 Reviewed-on: https://go-review.googlesource.com/c/go/+/189778 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
Just in case golang/go#21291 happened. roots#86 (comment)
I may be in the minority, but I'd actually like to propose the opposite. Functions with named returns should always use bare return. Otherwise, it just looks like the code is lying. You assign values and then potentially silently overwrite them upon return. Here is a bad piece of code to illustrate what I mean, func hello() (n, m int) {
n = 2
m = 3
return m, n
} If you'd just use a bare return there, the code makes sense again. |
@millerlogic I think that would be far too agressive. For example, there's nothing wrong with code like:
I also think your point might fit best as a separate counter-proposal, since you're suggesting the opposite of what the current proposal brings forward. |
@mvdan Good point, I think there is a middle ground which doesn't involve demonizing them. I think I read an idea similar to: not explicitly returning a value if you previously assigned to the return variable. It might even be implemented somewhere, but I never hit it. So that would mean my hello example would error without a naked return, and your example would succeed because foo or bar weren't assigned to. |
I think these should be removed from the tour of go, that way newer go developers aren't encouraged to use these. In practice they're just a cognitive tax. The few I've seen always required my brain to say "wait what?!...oh yeah, naked returns and named return values" I understand maybe leaving them in the tour so everyone knows, but there's an entire page dedicated to them. |
so.. variable shadowing is the problem, but named return values + naked return got to blame.. |
This is actually the one situation where shadowing is rarely a problem. The variables aren't shadowed in the top-level scope of the function, and if they're shadowed and there's a naked return in a sub-scope, it's a compile-time error. The main issue is if the variable is referenced from somewhere else, such as a closure, and then is accidentally shadowed somewhere, but that problem is not at all unique to named returns. |
why not just add a special return syntax for naked returns? That way there is no cognitive overhead of checking named returns since the special return syntax already implies that. Something like Bikeshedding ensues. The goal here is to differentiate naked returns from void returns. Also this can be opt-in to keep working code working and eventually turned into a lint or error. |
Removing an existing language feature requires a clear consensus that it is harmful in some way. For example, the feature might be widely misunderstood, and might lead to many bugs in existing code. I don't see that here. I understand that people don't like bare returns--I'm not especially fond of them myself--but I don't see people reporting bugs due to bare returns. So this is not a change that we are going to make, and I'm going to close this issue. Thanks. |
(I couldn't find an existing issue for this, so please close if this is a duplicate and I missed it.)
I propose getting rid of bare returns. Named return values are great, keep those. Bare returns are more trouble than they are worth, eliminate them.
The text was updated successfully, but these errors were encountered: