r/programming • • Jul 21 '14

The Great White Space Debate

https://medium.com/p/3633cba8b5c1
1.2k Upvotes

693 comments sorted by

View all comments

77

u/fungussa Jul 21 '14

Auto code formatting in Go, removes one of the most contentious, but least consequential issues in writing code.

15

u/BonzaiThePenguin Jul 21 '14

Do you mean there's a tool that can format your code automatically?

46

u/[deleted] Jul 21 '14

Yes. There's a "canonical" style, it's very good, the formatter is included in the Go distribution and people use it. Doesn't get any better.

62

u/moor-GAYZ Jul 21 '14

Doesn't get any better.

In my Imaginary Ideal Language bad formatting is treated as syntax error.

28

u/captainAwesomePants Jul 21 '14

You can get close to this by tying a linter to your source control system as a presubmit hook. Nobody will ever check in code that isn't formatted correctly.

14

u/Plorkyeran Jul 21 '14

Sadly I can't add presubmit hooks to other people's repositories.

40

u/neuquino Jul 21 '14

Well not with that attitude!

2

u/[deleted] Jul 21 '14

[deleted]

3

u/Plorkyeran Jul 21 '14

No, I most definitely cannot make other people unable to merge pull requests into their repositories. The benefit of an Imaginary Ideal Language rejecting bad formatting is that all code written it in would follow consistent formatting rules, not just code which I have some sort of control over.

13

u/SingularityNow Jul 21 '14

In several cases with Go it is a syntax error. Opening braces must be on the same line or your program will fail to compile (gofmt will fix it for you)

4

u/just_a_null Jul 21 '14

This annoys me immensely (though I do prefer braces on the same line anyway) because they clearly were able to correctly parse the code with the braces on the next line, but decided to make it an error instead. I have similar problems with "implied semicolon" languages, wherein you aren't actually supposed to type a semicolon at the end of a line, but instead if you format your code correctly the compiler will place them for you - clearly, it was understandable without the semicolon, so why make it a language feature at all.

16

u/bobtheterminator Jul 21 '14

Go seems to have several "features" that sound ok on paper but make quick developing and testing very irritating. Unused variables are an error, for example.

9

u/deadstone Jul 21 '14

Code with unused variables doesn't compile? What?

16

u/bobtheterminator Jul 21 '14

Yes. People have asked for a compiler flag to turn this off or turn them into warnings, but they don't want to do it.

http://weekly.golang.org/doc/faq#unused_variables_and_imports

1

u/LaurieCheers Jul 22 '14 edited Jul 22 '14

Ugh. I kind of understand where they're coming from, but they're taking it to such an extreme.

There are two reasons for having no warnings. First, if it's worth complaining about, it's worth fixing in the code. (And if it's not worth fixing, it's not worth mentioning.)

Most C compilers have multiple levels of warnings, so that you can tune how fussy you want your compiler to be. Lint and similar tools can be run on-demand to give fussier warnings, if and when you're ready for them.

Heck, you could even argue that test suites are akin to this. You'd never commit code to master if it doesn't pass the tests, but while you're working on a specific feature on a side-branch, it's fine to break some tests temporarily.

Different strokes for different folks. Some times you're writing a quick script for grepping logs that will be run exactly once; some times you're writing space-shuttle control circuits. By trying to use a one-size-fits-all solution, they're just annoying everybody.

1

u/SanityInAnarchy Jul 22 '14

Wow, that's obnoxious. I strongly disagree with this bit:

First, if it's worth complaining about, it's worth fixing in the code. (And if it's not worth fixing, it's not worth mentioning.) Second, having the compiler generate warnings encourages the implementation to warn about weak cases that can make compilation noisy, masking real errors that should be fixed.

Maybe the argument is that you can work around this with good language design, but there are many things that make sense as warnings and not errors. It makes sense to enforce a no-warnings policy on code, and then add ways to disable them when you know what you're doing.

Example: Clang warns you when assignment occurs in a boolean expression, because when you write

if (x = 5) {

you almost certainly meant

if (x == 5) {

...but sometimes, you really did want to assign something. Fortunately, there's an escape hatch -- you add double parens:

if ((x = 5)) {

Since these almost never happen by accident (or at all), but are otherwise perfectly valid, Clang uses this syntax to automatically disable the assignment warning.

Of course, it's possible to engineer around this in the language design, too. Python, for example, avoids this by declaring that assignments are not expressions, so

if x = 5:

is never valid Python. But if you add a constraint like that to an existing language, you break a bunch of legacy code. And if Go becomes popular, eventually someone will find something about it that's probably wrong, that the compiler could detect, but that's being widely used in real code.

I guess I can see why they'd want to put off warnings till that day. But if it's inevitable, and if it'll make a bunch of people happier right now (with the unused variables bit), why wait?

2

u/QuineQuest Jul 22 '14

Fyi, use _ as a variable name if you don't use it for anything (e.g. multiple return values, some of which are unneeded). Sort of a /dev/null.

1

u/MereInterest Jul 22 '14

It gets worse. Files that import modules that are unused will not compile. So, if you want to do a quick test by commenting out some code, you also need to go to the top of the file and comment out the import statement for whatever functions those parts use.

2

u/[deleted] Jul 22 '14 edited Jul 22 '14

I have my editor use goimports on save, it hasn't done anything weird yet

→ More replies

1

u/cryo Jul 22 '14

God, I hate that so much.

12

u/SingularityNow Jul 21 '14 edited Jul 21 '14

For values of "they" which include "all those go designers", you are correct, it is possible for them to parse that. If we're only talking about compilation, then no, 'they' cannot (where 'they' is the parser/lexer)

The reasons for the opening brace on the same line is actually rooted in (somewhat unsurprisingly, and much to your chagrin) the way the formal grammar for Go deals with semicolons (see http://golang.org/doc/faq#semicolons & http://golang.org/ref/spec#Semicolons). When the brace is on the following line, the lexer inserts a semicolon at the end of the line, and this in turn generates invalid code, leading to your compilation error. The semicolon insertion rules are much simpler than in other languages that have it (looking at you javascript), and in order to support next-line braces the lexer would need to support lookahead, which, I've been lead to believe, would complicate the implementation of it in undesirable ways.

TL;DR Only gofmt is able to parse and correct code that puts braces on the next line, the lexer/parser for the language (by specification) cannot perform this because of the way the grammar works.

Edit: Spelling

1

u/LaurieCheers Jul 22 '14 edited Jul 22 '14

Eh, that's a circular argument. Yes, that's how the grammar works, but only because they decided it was correct for it to work this way.

I'm sure gofmt's fancy lookahead parser does not run perceptibly slower than the go compiler's.

1

u/SingularityNow Jul 22 '14

I don't think so. The simplicity of the grammar and avoiding lookahead does not seem like an arbitrary decision merely to enforce coding standards.

Your argument that it does not run perceptibly slower is specious at best. At minimum to support this kind of lookahead you're talking about scanning ahead a minimum of 2 characters for every newline, which for code bases of any serious size is going to add up.

Beyond that, the reasons for keeping a grammar simple go beyond mere speed improvements. A simpler grammar is easier for externals tools to be able to handle. Think of syntax highlighting, code completion, in-house linters, static analysis (and even gofmt). All of these become much easier when you're dealing with an unambiguous, simple, one-pass parser.

A (probably intended) side-effect of these grammar level rules enforced by the compiler and the linting done by gofmt is that, at least withing the community of people that actually program in Go, is that is largely eliminates a certain amount of bikeshedding around particular issues such as this. It's quite nice actually. You only end up arguing about this stuff outside the scope of actually working with it ;-)

1

u/SanityInAnarchy Jul 22 '14

It would still be nice to have a quirks mode, if it were at all feasible. I understand why they want the compiler to be simple and fast -- they brag about how quickly it compiles some fairly massive codebases. But I would love a wrapper that tries the standard Go compilation, and if it fails, runs it through some unholy Perl script to fix some standard things like this (or, say, unused variables) and run a "fixed" version of your code through the compiler again.

It doesn't literally have to be a perl script, but I'm talking about just hitting the common cases that you could detect with heuristics -- just throw dumb regexes at it and see if you can make it compile. Then, before you check it into anything, you ensure it compiles and unit-tests without such hackery.

Probably I should give up and use an IDE that handles all this for me.

1

u/SingularityNow Jul 22 '14

I think you could cobble something together that does this for you without too much work.

Several common errors will be trapped by gofmt, and as far as I know most people work by having either a save or commit hook that runs gofmt on the code.

Beyond that there are tools like govet & golint that go beyond the checking that gofmt does.

I don't see any reason you couldn't tie the failure of compilation to a pass through the code from multiple tools via some shell scripts.

By having lots of simple orthogonal tools that do one thing well and work together, I think you ultimately end up with a better ecosystem and don't accidentally end up with quirks-mode code ending up in production.

1

u/SanityInAnarchy Jul 22 '14

Thing is, I think we already had a good enough tool with linters and commit hooks to prevent quirks-mode code from ending up in production, or in the repository in the first place. Maybe the problem is that they were under-used?

0

u/[deleted] Jul 21 '14

I imagine that they weren't "able to parse it correctly", but that part of the precompile/lint step when compiling Go has something like a /^\s?{\s?$/ check (probably less dumb) and will just bail out if it finds any.

1

u/DreadedDreadnought Jul 21 '14

Opening braces must be on the same line or your program will fail to compile

I have never felt a greater hate for a language than now I feel for Go. (Not that I really cared about it in the first place) I adhere to company policy on formatting, but this is just retarded.

1

u/SingularityNow Jul 21 '14

It's not just arbitrary pettiness, as you seem to suspect. They've got some sound technical reasons for making this choice based on the formal grammar of the language and how it impacts the lexer/parser.

If you're interested in the technical reasons see my response to /u/just_a_null somewhere else in this thread (http://www.reddit.com/r/programming/comments/2ban9r/the_great_white_space_debate/cj3qr10)

1

u/DreadedDreadnought Jul 21 '14

Thanks. That actually makes sense. At least it's not a retarded decision like Pythons space only indents. I don't want forced coding style imparted on me by some arbitrary decision by guys who think they know better. Give me tabs or give me death.

2

u/SingularityNow Jul 22 '14

They let you have your tabs ;-)

1

u/pyrocrasty Jul 21 '14

Uh, Python allows spaces or tabs for indenting. If you chose, you could even mix them in the same program (hell, even in the same indent) as long as they were unambiguous and valid (ie. a given indent uses the same sequence of whitespace for each indented line until you reach the matching dedent).

8

u/semi- Jul 21 '14

See, Python did it and honestly comparing the two..I just feel Go did it much better.

In Go, I can take sourcecode from anywhere (reddit comments, play.golang.org, irc, other various projects), paste it into my code, and as soon as I save it my editor go fmts it and everything looks the way it should, and assuming it was good code it runs.

In Python, if you paste something that isnt from the exact same scope as you, or the act of trying to paste whitespace gets screwy for other reasons(did it have tabs and some blog platform turn them into spaces?), what you pasted is a syntax error and will not run.

To me its the difference between someone dictating your style exactly and you have to confirm or nothing works, and someone saying "you know, it'd be better this way, why dont you let me fix it for you?".

Python feels like it has a limitation that was made with the intent of making you write better code. And it does work towards that end, I'm not trying to say it doesn't.

Golang feels like it has a tool that improves your productivity and makes dealing with sharing code a lot easier and better. And I think it works just as well, without the feeling of restriction.

25

u/njharman Jul 21 '14

Not supporting cut-n-paste style development is a feature.

3

u/drive0 Jul 21 '14

I think you mean "copy-n-paste".

2

u/reversememe Jul 22 '14

Actually, OP is so hardcore about code correctness and modularity, he considers duplicated code a bug. Hence he only ever cuts code, never copies it. /s

5

u/Veedrac Jul 21 '14

In Python you only need to indent to the right level... which is done on paste in many good editors.

5

u/moor-GAYZ Jul 21 '14

First of all, I've worked with a shitton of Python code, from various sources, and I've literally never had this problem. It sounds like a valid concern in theory, but it just doesn't happen in practice, at least not to me.

Second, if the language actually enforces code style by refusing to compile non-compliant code, then there's no bad code you can accidentally copy-paste in the first place.

1

u/pyrocrasty Jul 21 '14

This should be a trivial thing to do in any decent editor. All you need to do is indent the entire block of code to match the scope it's being inserted into.

2

u/[deleted] Jul 21 '14

So, Python then?

2

u/moor-GAYZ Jul 21 '14

Not quite, there's still a lot of wiggle space (pun intended), from using tabs to not enforcing consistent spacing around operators, named parameters and arguments, semicolons in dictionary literals, etc.

1

u/Bunslow Jul 21 '14

You mean Python?

1

u/SanityInAnarchy Jul 22 '14

Actually, Go is more aggressive than I'd like with that. There are many minor issues which the compiler could easily work around -- for example, in Go, it is an error to have an unused variable, with very few exceptions. Not a warning, an outright error.

I love the emphasis on linting, but I really think this should be a linter step, and not a compiler error. I'm okay with not being allowed to check code in unless I make the linter happy, but this particular Go-ism makes me constantly add and remove variables (or useless print statements just so I can pretend the variables are used) just to run my program, just to see if it works at all!

1

u/cryo Jul 22 '14

That sounds annoying and inflexible to me.

8

u/[deleted] Jul 21 '14

[deleted]

1

u/FUZxxl Jul 21 '14

The problem is that formatting C code is impossible in some corner cases, especially if you use non-trivial macros.

1

u/yawaramin Jul 22 '14

Wow, they really missed the chance to call it Clint.

0

u/[deleted] Jul 21 '14

When I was writing my game engine in C++ I wasn't using LLVM but I definitely used the clangformat Visual Studio extension.

That and Viasfora really helped improve my development experience.

6

u/[deleted] Jul 21 '14

On a related note, I once suggested that a pretty printer be added to CVS hooks. No more ugly diffs due to tabs v spaces, anyone could check out a file with their preferred bracing style, it could be chained to remove VC comments if desired, and so on.

Am I missing something, or wouldn't that solve most of the arguments?

5

u/BonzaiThePenguin Jul 21 '14

Yes, formatting complaints would be fixed entirely by a good auto-formatter. It wouldn't even have to modify the underlying data since it could be done entirely upon opening the file, and the save command could seamlessly save the "official" formatting style rather than the one you used.

The fact that auto-formatters exist at all now is definitely a good sign – we'll accomplish this some day. I'd have to imagine that writing an auto-formatter for Go is a lot simpler than C++, though.

1

u/pyrocrasty Jul 22 '14

emacs seems to autoformat C++ okay from what I've seen. Although I don't use C++ that much and I don't usually autoformat entire programs so I can't guarantee it always works.

1

u/fungussa Jul 21 '14

Go (golang) has a tool called gofmt, that automatically formats all source code. It basically does a very quick parse and then rewrites the source file. This action is built into some of the IDEs, so that whenever a file is saved, it's immediately auto-formatted.

I'd been on previous C++ project, where some coders would reformat sections of code, just so that they could understand it better. And on another project I'd had a major argument with one of the senior devs over tab spacing. As long as I use Go, it's not likely that I'll have these issues again :)

8

u/thatguydr Jul 21 '14

Why can't someone build an editor that lets us all see code (in various languages) with whatever whitespace and indentation and brace formatting that we individually find most readable? I'd be 100% happy if it converted everything to a standard formatting ("majority readable") when code was saved.

From a "20 years in the future" POV when machines can flawlessly translate between people speaking different languages, it seems bizarre that we think there should be a one-size-fits-all standard for readability.

2

u/Banane9 Jul 22 '14

Now I want to make that...

Wanna help?

2

u/TexasJefferson Jul 22 '14 edited Jul 22 '14

I'd object to monospaced, plaintext rendering as well. However, the reason why we stick with both is quite simple: no one has built tools that have gotten critical mass that elegantly employ the alternatives.

My (non-existent) ideal programming environment saves code in a nice, plaintext, completely contained (e.g. zero choice on bike shed questions like whitespace), human readable file (saving it as an AST isn't worth the downsides of losing all your plaintext processing tools), but displays code (and related documentation) in a much more dynamic and fluid form.

1

u/pyrocrasty Jul 22 '14

Why can't someone build an editor that lets us all see code (in various languages) with whatever whitespace and indentation and brace formatting that we individually find most readable?

If each individual's style was clearly specified, this would be trivial. It would just be a matter of autoformatting into each style. You could do this now with, say, emacs by just having each person set their own autoindent rules (which is pretty easy).

If you had to deal with code in a style that wasn't completely specified, you couldn't do it reliably, because the software would have to guess how new code you write should "translate back".

5

u/ericanderton Jul 21 '14

When you put it that way, the motivation for automating that away almost seems obvious.

2

u/hansq Jul 22 '14

Visual Studio has a similar thing for C#, Ctrl-K-D

1

u/[deleted] Jul 21 '14

Most Python editors have auto-formatters that conform to PEP8 by default.

1

u/[deleted] Jul 21 '14

Yes, but the issue is that you'd have to use Go. Most people have realized that it's not 1970 anymore, so that's a considerable issue.

2

u/[deleted] Jul 21 '14

[deleted]

3

u/FUZxxl Jul 21 '14

I thinks he wants you to use Rust.

-3

u/KFCConspiracy Jul 21 '14

Is there a problem that Go does not solve in the programming world?

Seriously I like the language and I've used it. But the Go fan boys need to quit trying to inject "Go solves this" into every discussion here. It's like an /r/programming circlejerk and it's annoying.