-
-
Notifications
You must be signed in to change notification settings - Fork 113
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: Clothe naked returns #285
Comments
"clothing" returns is such a neat little name for this rewrite :) I'm fully behind your rationale. I avoid naked returns practically everywhere. I'm not sure this belongs in a formatter, though, even though it's meant to be more aggressive and strict than gofmt. You could squint a bit and say that such a rewrite would increase consistency, but the rewrite itself adds new identifiers to the syntax tree, which is not something that gofumpt has ever done before. Another way to look at this is that such a rewrite is only safe to do with type information. gofumpt works off of the syntax tree alone, so it would have to start keeping track of what function body it's currently in, whether it's got any named result parameters, and what their names are. Not terribly expensive to do this, but it would be the first instance where we'd need to make gofumpt aware of types, further indicating it's not a formatting concept. All that said, if this were added in another tool, I'd use it. Which tool that would be is a good question, and I'm not sure. If that's how you ended up suggesting it here, I completely understand. |
Thanks @mvdan. I appreciate your arguments against including this in this tool. They're in line with some of my skepticism about including it here as well. Let me offer a small response, and some additional thoughts:
Probably the next best option for another tool would be a |
I think you're right that most people would see this as a style issue, and the line between formatting and styling is a fuzzy one. I also agree that golangci-lint wouldn't be a good home for such a rewriter. Personally I'm not a fan of that tool, so I'd avoid using the rewriter even if it did exist there. I'm open to accepting a contribution for this. Would you be able to do a brief study on how prevalent naked returns are across popular Go codebases? My personal impression is that they are very rare, so adding this to gofumpt would not be controversial. But I have no idea if other codebases use it often or perhaps even consistently. It would be particularly interesting to see if any Go repos use gofumpt and use naked returns with some frequency. |
One option we didn't talk about is an analyzer (https://pkg.go.dev/golang.org/x/tools/go/analysis#hdr-Analyzer) which could then be added to gopls or other "meta linters" easily. However, the bar for adding these to gopls is somewhat high, since they need to be bundled at compile time. So far I think they've only added staticcheck and gofumpt, and gofumpt isn't even an analyzer (yet). |
|
Here are some very high-level, preliminary results from my investigation. I've counted total number of clothed and naked returns, as well as the number of functions that mix naked and non-naked returns. The discrepancy between total and clothed+naked represent returns in functions that have no return values. I've also excluded generated code where it's easy to identify, and the I've compared three code corpora:
I used this very unsophisticated, thrown-together tool to do the analysis. Update: The majority of the naked returns in the grank list come from a single repo: https://github.com/tencentcloud/tencentcloud-sdk-go If I pull that one out, the results look like:
|
Did you mean to make that open source, or is the link perhaps incorrect? Ignoring that SDK module seems fine; the examples in the README don't even follow gofmt :) Though note that grank appears to heavily skew towards libraries. The top ten are all libraries, and out of them six are primarily for testing, for example. I would personally think that large non-library projects are significantly more relevant than testing libraries. For example, here's a rather simple ranking based on stars and forks on github: https://github.com/mvdan/corpus/blob/master/top-100.tsv ~1% across popular repos and ~0.8% across those which are aware of gofumpt sounds like what I would expect, and that doesn't worry me in terms of giving this a try. ~2.7% in std is definitely more worrying, though. I think we'd have to implement a first version of this, run it across some good codebases like std, and see whether the result looks better or not. If we're not sure, then we shouldn't release it. |
I did. It's public now.
I'll follow up with an analysis of some of these. |
Took me a while to get back to this, but I've now run the naked return analysis on the collection of repos at https://github.com/mvdan/corpus/blob/master/top-100.tsv:
|
This may not be a good fit for this tool, and even if it is, it may be controversial. It may even be technically infeasible for reasons I haven't been able to imagine yet. So this is as much an RFC as a proposal.
Proposal
But to the meat of the matter: I'm proposing that
gofumpt
rewrite naked returns to no longer be naked. I think this can be a simple matter of copying the names of return values from the function signature to any naked return statements. Example:would be rewritten to:
Rationale
IMHO, naked returns are one of the worst features of Go. I know I'm not alone in this, although I haven't done any sort of formal survey. For a language that values readability, this feature seemingly always goes against that ideal. Granted, for trivially short functions (like my example above), the naked return doesn't really hurt readability that much. The problems arise for much longer functions. But even in these short cases, adding the return result doesn't seem to hurt readability, either.
The only argument I can think of in favor of naked returns is the popular "less typing". But by having a tool like
gofumpt
do this, those who like less typing can still have their way, without hurting readability.Possible Problems
I've spent some time trying to find places where the simple rule of "copy the named return values to the naked return statement" might break things. I can't think of any. There are a few places where a naked return might be ambiguous, with regard to shadowed variables, but these are already prohibited by the compiler. So I think we can assume that any valid Go code can apply this rule safely.
The text was updated successfully, but these errors were encountered: