Seems a lot of these rules focus on removing empty lines. I find empty lines let the code "breathe" a bit.
Without them, it's a massive wall of text, sometimes. Well, often times.
It's interesting you can address the "wall of text" problem in 2 ways.
1) Get IDE strategically insert vertical whitespace, for example right after function definition, and before function body. It does not need to be a full empty line, half of line height would do.
2) Or other way around, if you have an empty line before function body starts, IDE could narrow the height a bit, because this does not need a full-size empty line. Actually I wonder if there are IDEs around that play with variable line height for empty lines.
The above would allow folks who feel they are starved for vertical space to condense the code more, without impacting others who feel they have plenty of vertical space, and would like to break the "wall of text" with white space breathers.
Currently Intellij (GoLand) will strategically fold the `if / return err` pattern that Go code is littered with, so the whole "keep it on single line" point is moot for somebody using an advanced IDE that automatically renders the code in way to reduce visual clutter.
Put another way, writing clean code is like writing prose. You need to clearly break down your thoughtt, whether its sections, paragraphs, sentences, and fragments, or files, functions, blocks, groups of lines.
Drove me nuts when working in a C# code base that controlled newlines because I had to break up related thoughts.
Yeah. And when I write comments, I do it in explanation of the chunk of lines below which perform a particular idea. The newline after that chunk is necessary to break up the chunks to give room for another one below, etc.
I really hate the c# code style of a new line for both open and close braces, especially in an if then else statement. Pushes people to use long ternary statements instead.
I prefer ifs to ternarys because, more often than not, I want to easily add and remove statements to the body of the then or else as I'm working things out.
Empty lines let you split your code into assignment/initialization, logic and parameter validation, without requiring you to split everything into tiny functions.
I agree that empty lines can help. I've been careful to only remove empty lines which, in my opinion, don't help when structuring the code or making it more readable.
If you have examples where gofumpt is being a bit too aggressive, I'd like to hear about them. I've corrected, and even removed, some of gofumpt's rules in the past thanks to user input.
I use gofumpt for all my go code (have been for at least two years), and I use empty lines for structure. Out of the tens to hundreds of thousands lines written, I don’t recall a single instance where an intentional empty line was removed. I doubt gp’s comment is based on experience. Another giveaway is the “seems” at the very beginning.
Am I understanding correctly that: gofmt(gofumpt(code)) == gofumpt(code)?
If so, I don't get the negativity in these comments centered around diverging from gofmt. A developer could make any of the decisions that gofumpt made.
If that's the case, then it's even more "gofmt" than "gofmt".
The important thing about "gofmt" is that it's the only canonical way to format an AST, so anything that fights with gofmt would undermine that and never get traction in the Go ecosystem.
Operating in the space where gofmt hasn't completely made up it's mind is a great way to experiment with potential improvements.
Before gofmt, programmers were allowed to have accents. Teams were allowed to decide their preferred style.
Since gofmt, we "avoid bikeshedding" by disallowing the developer from adding any value via formatting.
Dozens of languages that are far more sophisticated than Go have adopted this boneheaded approach (typical Go philosophy) in the years since gofmt appeared.
It'll be a while before I retire, but when the time comes, I am preparing for this to be the hill I die on.
> disallowing the developer from adding any value via formatting
formatting doesn't add value. no one formatting is going to please everyone, so it follows that any formatting is going to piss someone off. So I think the point from the Go team is to remove that distraction and let people focus on whats actually important, the code itself.
Exactly. I prefer writing with double quotes as they are easier to hit for me. When/if the formatter changes them to single quotes I couldn't care less. I can accidentally miss-indent something and the formatter will catch it and fix it. Why spend mental energy making sure I'm perfectly writing trivial things when I can focus on the important stuff?
I personally am looking forward to the go tool replaces `go run` etc. for a version that makes additonal whitespace and misalignment into a compiler error!
I don't understand your comment. In the first sentences you seem to be in favor of code formatting (me too), pointing out the benefits, then towards the end you seem to be against it.
There's no accounting for taste to be sure, but I for one won't be patronized by a dumb tool. Formatting is for my team and me to decide, and no one else.
Write code as if the next maintainer is a psychotic murderer with your address.
Honestly I see gofmt as a lightweight pep8 (from python) and I prefer languages to follow a standard for style and such.
I kind of hate when I see people adopt a different style than the rest of the codebase moreso than anything else though. Keep things consistent, I dont want a zoo of inconsistent code styles.
> A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important.
> However, know when to be inconsistent – sometimes style guide recommendations just aren’t applicable. When in doubt, use your best judgment. Look at other examples and decide what looks best.
Not everyone agrees with this, but just citing pep8 this is one of the more important points to me.
Ye. This is agile deep down removing the fun from programming with all its toxic processes. Programmers are the worst when it comes to forcing their dogmatic believes on others.
This, I really don't get why people want to enforce uniformity, a room filled with people with exactly the same accent is a boring room. Most teams I've worked on slowly converge to a "house style" in any case, and if you're on the team, your personal preferences are a part of that. Not some committee.
"I really don't get why people want to enforce uniformity"
This is engineering, not food choice or movie accents. I don't want your second style in my code for the same reason that if my physical project uses metric tooling, I don't want the intern to come screaming in with imperial tooling, and then get huffy when I complain and ask them to recast their work in metric. Yes, it's true, there's absolutely nothing your imperial tooling can't do... but I still don't want it in my engineering for no benefit.
Engineering innovation is not harmed by being pushed above the basic level of which kind of tooling it uses.
I wonder how many people complaining are actually routine Go programmers. These rules are pretty sensible and clearly written by an experienced Go programmer. To the extent that my code would be modified by this tool, it isn't much. Many of the rules are just unsightly in Go code in practice and many of them I've already wondered why gofmt doesn't already have. For instance, the rule around newlines and brackets; I've often accidentally had a function end with a newline, but it never looks good, it's never something I'm like yes, let me fight for this and I've manually removed it as soon as I've seen it. If someone on my team really went to bat against these rules (and note the "really went to bat", I'm not talking quibbles here & there, we've all got those) I'd have questions about their ability to do basic cost/benefit analysis in such a process.
And, if it isn't engineering, then by all means go nuts with whatever you like. But I think your question only has meaning in a group context, because if you're not in a group context, who cares in the slightest what the non-existent group thinks? I've got plenty of personal projects that I in my own engineering role wouldn't consider to pass even basic engineering muster. You should see my electrical "engineering" work; I would feel dirty if I didn't scare quote the term "engineering". I'm not very good. Tends to look more like a hollywood bomb than anything you see linked in the sort of YouTube video that shows up on HN every so often.
It depends on the formatter you're using. If it's strict about line width you'll end up with a lot of noise in the diffs. Prettier will re-format single-line lists that goes one character over the threshold and then re-condense them once it's able to fit under that threshold. It's not uncommon for a change that adds three classes to three different elements to become a 20 line diff.
Otherwise people sharing that criteria will never fix minor code style issues because "it was that way before, and it's such a minor thing, and it makes my merge harder, please accept the review and ship it don't be unreasonable", and of course we are "reasonable" and end up with thousands of "minor things" over time and the more there are the more people feel it's fine to leave shit in, the less comfortable they feel with the code until eventually they all quit and leave the mess to someone else.
I don't even want to imagine how bad the shitshow is going to get as AI coding assistants gain marketshare.
gofmt's normalization of code formatters was the single greatest achievement Go has to its name, and Prettier was a clear improvement on it. If fixing this crap is bothering anyone's laziness or their artistic sentimentalities then they better get to solving the issue where we're still storing code in source control instead of ASTs and letting the editors render them however the user wants.
I agree with this 100%. I would extend it by saying that one you make formatting mandatory, the rules themselves don't matter, as long as they are the same for everyone on the project.
One could also make formatting automatic through git hooks and then every one can override their local formatting rules to their liking without breaking the common rules.
Eventually you realize that what's really needed is AST-based semantic revision control. Text is a lowest common denominator that all programming tools should go beyond, not just the compilers.
Take PEP8 for example which is Python specific. PEP8 has a rule that code shall not exceed 79 characters. This has the added benefit that on a standard 1080 monitor you can see two Python files side by side without horizontal scrolling. This also has the added benefit of being able to see code diffs without issue.
I can see why certain choices are made but only matter if they have sound reasoning and arguments for them.
You really want to argue that shrinking font from a standard font size will produce legible text like that?
The argument is against super long lines. I think Clean Code suggests something similar to the effect of if you have more than three arguments for a method you are better served taking a class as the argument.
I've found that it's almost always a good idea to return fmt.Errorf(...), adding context to the error. Otherwise error messages are too generic and it's hard to figure out what's actually wrong. Then it doesn't fit on a single line anymore.
github.com/pkg/errors is dead — it’s been archived for a long time, and doesn’t incorporate go 1.20’s multi-error wrapping. Better switch to fmt.Errorf in new projects going forward.
It doesn't? It is only a tiny tiny bit longer than the fmt.Errorf() by itself, which is surely one line, right? The key thing is to then have your syntax highlighter set up to specially handle these lines, to help you 1) know that they are there, 2) know that they are structured correctly, and 3) ignore them (which is safe now that you can see it exists and is in the right format). Unless you set these up as one line, your Go code gets littered with 3x (or even 4x if you add a blank line after each block, which starts to feel better) as much error handling lines as non-error lines.
How is having chunks of code smashed into the tops and bottoms of a blocks good for improving readability? Why should the visual relationship between and main() and "a" be stronger than between "b" and "c" if the author doesn't want it?
> How is having chunks of code smashed into the tops and bottoms of a blocks good for improving readability?
How is having a random newline at the top and bottom where there is already a clear separation between function signature and implementation via braces and the guide of the first indentation, helping readability?
All it does is steal valuable vertical space away from things that matter.
I hadn't really considered that people might want to do this. From experience reading and writing Go code for ~8 years at multiple companies, the only times I've seen leading or trailing empty lines in blocks have always been either inconsistent or unintentional, and usually both.
Are there Go codebases that stick to the formatting you show, out of curiosity?
Either way, please file a bug. Perhaps others can chime in there if they also use the same style.
I've seen this once across many Go codebases, it was someone who even a year in writing Go still refused to consistently name constants and global variables without snake_case, among other similar behaviors.
Support for allowing configuration of such a thing would be a misfeature if I was to be asked.
gofumpt will never have formatting knobs, following gofmt's design. But if one of gofumpt's rules forbids a style which is reasonable even if it's not very popular, we might want to make the rule more conservative or remove it entirely.
As far as I understand, that's a consequence of the automatic insertion of trailing semicolon by the lexer, not a decision by gofmt. It's explained here:
https://go.dev/doc/effective_go#semicolons
I see. That doesn’t seem very sensible in potential-beginning-of-block contexts, in particular in the if case where an implicit empty statement is deduced after the condition.
> That doesn’t seem very sensible in potential-beginning-of-block contexts, in particular in the if case where an implicit empty statement is deduced after the condition.
Are you referring to C style if statements where you can elide the braces?
In go the braces are mandatory, so I don't think that really applies.
I was referring to the Go documentation linked above:
> One consequence of the semicolon insertion rules is that you cannot put the opening brace of a control structure (if, for, switch, or select) on the next line. If you do, a semicolon will be inserted before the brace, which could cause unwanted effects.
I was assuming that the “unwanted effects” are not simply a syntax error.
there is no "visual relationship" between main and a, indentation differentiates blocks, empty lines at block begin/end serve no purpose, please stop doing this
I checked the interfacer and I am a bit sad to that it
1) Is "deprecated" and literally the first sentence states its use is discouraged because often such suggestions are misleading and bad advise.
2) From the readme it appears it just suggest to changes of parameter types in functions to existing interfaces. I was hoping to see something that suggests interface definitions from existing types based on whether share methods with same names.
About 2) I guess it is indeed kind of unnecessary as such suggestions are kind of trivial. On the ither hand I recently started to learn how to use interfaces and I have kind of a difficult time to wrap my head around how to make idiomatic use of that concept. So even such trivial help would actually be of some use to me, simply because it removes some cognitive load and I be able to see many examples (even potentially bad, but compiling ones) in front of my eyes.
In the roadmap section[1] the author says it's more of an experiment with a possibility that some of the rules might end up in the original 'gofmt' tool. While I agree that Go having a de facto formatter built in is wonderful, there are some absolutely fantastic additions in 'gofumpt' that I do hope wind up in 'gofmt'
very much so imo. the standard formatter is one of the things go very much does right
my protests against requiring this, as additional friction for our OSS contributors especially, unfortunately fell on deaf ears. unfortunately i just don't have the energy to beat my more pedantic coworkers over the head with the notion that if these additional formatting rules are that important to them they need to do the legwork to pull them into mainline gofmt
nah, that's actual work. an additional hurdle in the dev environment for some random formatting things that nobody will ever notice though, you can enforce that in a few lines of CI scaffolding, so into the checks it goes
It's not quite as simple as that :) I think upstreaming half of gofumpt's additions to gofmt would be reasonable, but the person who wrote and maintains gofmt is Robert Griesemer, who continues to be quite busy with generics. They are still actively fixing typechecking bugs and performance issues, as far as I can see.
I think it's hard for anyone to justify pausing or distracting the generics work in favor of upstreaming parts of gofumpt. At the end of the day, gofumpt works today - it's just a bit awkward to have it as a third party tool.
That said, it is on my radar to talk to him and make a plan for upstreaming.
Edit: to clarify what I mean with the above: I of course could do the legwork to port my formatting changes to go/printer, the guts of gofmt. The reason I mention Robert is that he'd be the one to consider and approve each formatting change, and review the code changes and tests. That work is trickier than it sounds, because you have to think about the possible effect any formatting change would have on all kinds of existing Go code out there.
For open source projects in general, and the Go project in particular, I think it is easy to underestimate how much maintainer time is consumed discussing & considering whether a change should be made.
No ty. I don't like strictness, the strictness of gofmt and the forced layout is enough.
Especially I don't like being told to do redundant tasks like commenting obviously named functions.
The only thing I'd like to have in gofmt is what goimports does, sorting and dividing imports by local and remote.
What I absolutely hate is an enforced 80 char limit. I write on 4k, I can afford much wider, even when viewing on mobile.
But whatever, that discussion is pointless anyway. Ty but no ty. Moving on.
You might be getting confused. gofmt does not warn about lacking comments, that was golint, which has since been deprecated.
gofmt does not divide or re-join imports into groups, but gofumpt does :)
Neither gofmt nor gofumpt enforce a character limit on lines. Some form of line length limit is the most common gofumpt feature request by far, but one that I haven't been brave enough to release in any form.
Perhaps read gofumpt's README, it has a lot more information.
Without them, it's a massive wall of text, sometimes. Well, often times.
It's interesting you can address the "wall of text" problem in 2 ways.
1) Get IDE strategically insert vertical whitespace, for example right after function definition, and before function body. It does not need to be a full empty line, half of line height would do.
2) Or other way around, if you have an empty line before function body starts, IDE could narrow the height a bit, because this does not need a full-size empty line. Actually I wonder if there are IDEs around that play with variable line height for empty lines.
The above would allow folks who feel they are starved for vertical space to condense the code more, without impacting others who feel they have plenty of vertical space, and would like to break the "wall of text" with white space breathers.
Currently Intellij (GoLand) will strategically fold the `if / return err` pattern that Go code is littered with, so the whole "keep it on single line" point is moot for somebody using an advanced IDE that automatically renders the code in way to reduce visual clutter.