1. 17

“Some observers objected to Go’s C-like block structure with braces, preferring the use of spaces for indentation, in the style of Python or Haskell. However, we have had extensive experience tracking down build and test failures caused by cross-language builds where a Python snippet embedded in another language, for instance through a SWIG invocation, is subtly and invisibly broken by a change in the indentation of the surrounding code. Our position is therefore that, although spaces for indentation is nice for small programs, it doesn’t scale well, and the bigger and more heterogeneous the code base, the more trouble it can cause. It is better to forgo convenience for safety and dependability, so Go has brace-bounded blocks.” - Rob Pike in this article.

Meta: Since I’m submitting a quote (not link), I decided to experiment by just putting it in text field with a link for people that want rest of article. They don’t have to leave site that way.

  1.  

  2. 17

    To me, the issue isn’t that it is an “objective” argument but rather that it is a “universal” argument. Go’s designers made a design choice based on their goals. That’s fine. The extended rationale that indentation doesn’t scale in general or work for heterogeneous environments doesn’t really follow. In fact, there’s no real need to make an assertion past Go when making a decision for Go.

    1. 20

      I would tend to think that, since you know that Python has significant indentation, you should embed any Python snippets in such a way that they won’t be affected by indentation changes in the code, such as by using the language equivalent of a heredoc or multi-line string, using explicit spaces and line breaks, or putting it in a separate file and reading it in.

      If their experience is that people just aren’t doing that even when they know they should, though, I’d say that breaking embedded Python code is the least of your problems.

      1. 5

        Using a heredoc or multiline string is not enough to avoid the issue. If you inject the Python snippet in already indented Python code, you have to indent the Python snippet accordingly, and this is not trivial. Your snippet can use tabs, and the destination can use spaces, for example. You also have to be careful with the indentation of the first line.

        1. 2

          Injecting some python code into some other python code by text manipulation sounds pretty bizarre. I’m not a Python whiz, but I’m pretty sure Python has proper plugin and importing functionality to allow you to not have to do something so hacky. I’m not saying that there’s no possible reason to do that, but if there is, I can’t come up with it.

          1. 2

            My take was that the Python was inserted into other code, such as Go code?

            In any case, once your language has reached the point where other people are embedding it, you’ve pretty much made it.

            (Edit clarification)

          2. 0

            I mean you have texttools and deindent in python, and you can write similar functions in other languages.

            It’s not trivial but it’s pretty solvable if you establish a pattern and add some validation

            1. 3

              Of course it’s solvable. But I think this is the kind of accidental complexity (and bugs) Pike is referring to. On a personal level, I have been programming in Python for years, and persuaded that significant indentation is great, until I tried Go with gofmt. Since then, I think the Go team was right about this. But anyway, I’m probably bike-shedding :-)

        2. 9

          Python has been my main programming language for years. I do like to explore though, lisps, rust, also I have spe t years writing c/c++ and also used Lua/Pascal with keyword based blocks.

          I think there is an argument to be made for braces or parentheses as block delimiters. It simplifies moving around pieces of code definitely. Also, since most code with braces/parentheses is indented as well, there isn’t much of a difference for people who rely on indentation. Also braces help formatting tools with the indentation which spare me some block shifting I usually have to do in python.

          While I find Python’s indentation based syntax at least readable, the indentstion syntax for Haskell is much more magic . I would wish Haskell community would use more braces-style Haskell

          1. 3

            Also braces help formatting tools with the indentation which spare me some block shifting I usually have to do in python.

            Exactly this.

          2. 15

            That’s not a very strong argument. So, there’s this one, very specific use case, with this specific tool, where sometimes things will go bad with languages that uses indentation for delimiting blocks. Therefore, using indentation to delimit blocks is bad. It just doesn’t follow. I had to google what SWIG even was.

            Plus I have very mixed feelings about the line “It is better to forgo convenience for safety”. Like, yeah, maybe, but safety without convenience will just not be used, so, not sure about the usefulness of this statement as a general guideline.

            1. 8

              Don’t even get me started on this issue.

              The end “product” might look more neat or clean but good code should have the following characteristics:

              • Easy to understand by anyone
              • Easy to spot semantics errors (possibly there is your IDE helping here)
              • Easy to define logical structures

              For me at first glance, I couldn’t for sure tell you whether a python snippet is correct or not, let alone if I didn’t write it.

              While with braces, it’s super straightforward (even when there are lots of them).

              It might be me but a good syntax shouldn’t be just a “pretty” or “fun” one, it should be one easy to remember and to look at.

              If you ask me, the same applies to static typing (another heated topic) but looking at code and having types guide me through whatever logic I’m inspecting/debugging is so pleasing and easy that the amount of comments needed (also thanks to good function and variable naming) decreases immensely.

              Navigating a huge pile of var here and var there, it’s just hard to know whether that specific assignment is wanted or merely a mistake.

              Might just be me, I don’t know.

              1. 11

                To be fair, if the code is so complex it requires more than a glance, the braces alone won’t save you. Having coherent indentation without mixing spaces and tabs will help with that.

                1. 5

                  I think the argument for keeping curly braces is pretty much the same for semicolons – they are both a pointless hassle, completely unnecessary in a world with things like “color displays” and almost all editors being indentation-aware in some fashion.

                  1. 4

                    The indention-aware IDE’s was the strongest counterpoint I thought of when reading this.

                    1. 2

                      Thanks!

                      1. 1

                        What exactly is an indentation aware IDE? And isnt it a bad thing that a language requires more complex tools to use it properly?

                        I might be a bit curmudgeonly, but I never got what the problem with parens was…

                        1. 3

                          Every decent lisp editor automatically indents your code

                          1. 1

                            Not really my point though. I think the simpler and more consistent the syntax, the easier it is to write tools around it. I’m thinking of stuff like paredit / parinfer.

                      2. 2

                        How well does this work? If I copy a block of code from one function that’s three levels in and paste it into a function where it should be two levels in, will it be two or three levels deep? Because whenever I’ve done this in C the indentation is initially wrong and needs to be corrected.

                        1. 3

                          I think the core argument is that IDEs/editors/LSP impls would be forced to get it right, because they cannot longer rely on braces to undo their own code garbling: I have lost track how often I had to correct indentation after pasting something, where usually the first line always ends up with either too much or not enough indentation.

                          Ideally the code-to-pasted should be stripped of any leading whitespace, except the “internal” one, and the position of your cursor at the target position should be the sole criteria to decide on the level of indentation.

                          I believe this could turn into a big benefit, even for curly brace languages.

                          1. 4

                            If I paste code at the end of an if block, how is the editor to know whether it is part of the if block or comes after? If there is a brace or some other marker, it’s easy for me to put the cursor inside or outside.

                            Here’s some code:

                            if conditionA:
                                code()
                            if conditionB:
                                morecode()
                            

                            I would like to paste “somecode()” into this function. Where do I put the cursor to add within conditionA and where to add between A and B?

                            1. 2

                              You put your cursor on line two, press p

                              1. 1

                                Two options:

                                • end of line 2 for A, beginning of line 3 for between A & B

                                • beginning of line 3 for between A & B; must add indented newline as part of A to paste into body of A

                            2. 3

                              You reindent to where you want it to be. The editor cannot know.

                              With braces your editor may be taught how to count braces and reindent properly (or call indent), and then you could argue “braces win”. I understand from your comment this isn’t common, but I think I could set my NeoVim up to do this quite easily.

                              However, copying code around and reindenting is such a trivial thing to do, that if braces could win by it, it’d be by a very narrow margin. So narrow that personal æsthetics concerning cleanliness is more important to some of us.

                          2. 6

                            For me at first glance, I couldn’t for sure tell you whether a python snippet is correct or not, let alone if I didn’t write it.

                            What happened to the idea that you could learn a programming language before expecting you would be able to understand code written in that language?

                            I never see Haskell criticised on the basis that Java programmers can’t understand it.

                            Have you considered that Python’s syntax isn’t difficult to learn and is very simple and easy once you’ve learnt it?

                            While with braces, it’s super straightforward (even when there are lots of them).

                            The fact that major security bugs have been created in curly brace languages due to indentation and braces being unaligned suggests to me that people look at the indentation and not the braces.

                            1. 2

                              That last point is a bit of a strawman since I never stated that curly have inherently no bugs.

                              Also lots of projects are/were done in C-like languages, so it’s clear that those kind of bugs are bound to happen.

                              1. 2

                                You claimed that not having indentation-based syntax makes understanding code easier. If that were true, there wouldn’t be issues like

                                if (x)
                                    goto fail;
                                    goto fail;
                                
                                1. 1

                                  I would use this instead:

                                  if (x) {
                                     goto fail;
                                     goto fail;
                                  } 
                                  
                          3. 13

                            You can’t call something an “objective argument” when your only evidence is “experience”. At the very least do a proper controlled study.

                            1. 7

                              I think I can if my definition is right. I go by popular usage of the words:

                              Subjective: Something that’s in one’s own mind whose form or reasioning outsiders cant see. Maybe also something derived from that.

                              Objective: Something in real world that’s measurable where we know we’re talking about the same thing.

                              Empirical: Builds on objective claims adding things like experiments.

                              The linked statement woukd be objective because it was based on real-world measurements we can all understand of language style and problems. It’s not scientific or emperical since there were no controlled studies and replication to be sure there was a causal link. This objective claim does get people thinking, though. It can also be starting point for empirical studies and claims.

                              That was my reasoning anyway.

                              1. 5

                                “Popular usage” is only an objective criterion if we accept your definition of “objective”. Which makes it a circular definition. “Objective” actually means “existing independent of or external to the mind” or “uninfluenced by emotions or personal prejudices”, as per Farlex. The argument you present sounds very much like the product of a particular mind, and very little effort has been made to examine it as part of a broader context.

                                Also, science isn’t rationalizing your claims with evidence. That’s just debate. Science is only unbiased when one starts from a clean slate and lets the evidence found speak for itself.

                                Finally, regardless of your intentions, these kinds of posts will always be seen as flamebait. This is something many people have a subjective view on, to little substantive end. But I appreciate that much of the response has been focused on the hard claims being made, rather than personal beliefs—even if it is ultimately personal beliefs motivating that response.

                              2. 1

                                I think it’s fine to say it’s an objective argument, but that doesn’t imply that it’s the most important argument. I think it’s a legitimate bullet point on a list of pros/cons, but a comprehensive list will have plenty of other bullet points too.

                              3. 5

                                I once liked python’s style, but then I met code formatters. Save your file, and your code gets formatted to the only correct form. This saves so much time and energy. Not only do you not have to think about code formatting, but nobody else has to either – and suddenly we don’t have to argue about standards or waste time in code review complaining about indentation.

                                This saving is impossible on python and other languages with whitespace significant blocks.

                                1. 3

                                  I came from Python to Go (and C, C++, Java, Pascal, etc. before), and my conclusion is the same.

                                  1. 2

                                    Why is it impossible?

                                    1. 1

                                      This is impossible to indent automatically:

                                      if True:
                                          foobar
                                      barfoo
                                      

                                      because the formatter cannot know if barfoo should be indented or not.

                                      1. 1

                                        Sorry, still lost. Why would it be impossible to know how to indent barfoo? It is at the same level as if so it should be indented as if statement.

                                        1. 1

                                          Ok. What about this?

                                          if True:
                                              foobar
                                            barfoo
                                          
                                          1. 2

                                            This is not a valid Python code so I’d say nothing or indent as it is (second line two levels, third line one level).

                                            I have difficulty coming up with Python code that would be valid and also difficult to figure out how to indent when copied. The only exception I can think of is to mix tabs and spaces in the same file which is bat shit crazy and you’ll find nobody reasonable defending this (you already have an error even if you don’t see it).

                                    2. 1

                                      impossible on python

                                      https://github.com/google/yapf

                                      1. 1

                                        Also, https://github.com/ambv/black, which has a philosophy similar to the go auto formatting tool

                                        1. 1

                                          Well, this looks like I’m moving the goalposts, but really I just forgot to specify well enough before.

                                          I’m talking about a formatter that can format the whole program code to a single correct form without changing the meaning. In whitespace-significant languages this is obviously impossible, since formatting and semantics are intertwined.

                                      2. 3

                                        I think a more general/abstract way of saying this is that indented strings don’t compose (easily). For example, given strings a, b and c, how can we construct an if/then/else with condition c and branches a and b? Concatenating the strings with some keywords and newlines will break if a and b contain their own indented lines (e.g. their own if branches created by concatenating). We could alter the strings, to find/replace some extra indentation after any newlines, but editing in-band metadata like that is dangerous; for example, it may corrupt string literals. To do so safely we’d need to actually parse the contents, which might be difficult considering they’re only fragments, the parse might be ambigious, etc. Since we’re doing metaprogramming, the strings may also contain artefacts for some metalanguage (e.g. CPP macros) which will break our parser.

                                        A more general solution is to use a more complicated datastructure which tracks indentation separately to the content, e.g. using pairs of (indentation_level, list_of_lines_or_blocks). This can work, but is more complex and requires programmers to write libraries for doing this in every programming language (most languages provide string concatenation by default). It also requires a rendering step to produce the final string (e.g. for writing to a file), which requires us to keep track of two different representations, and has the same parsing difficulties if we want to use existing strings of code in our metaprogramming (either read from a file, or because some other metaprogramming step rendered too early).

                                        Note that these metaprogramming problems are real. They may not be felt directly by day to day users of a language, and there is some merit to claims that metaprogramming should be avoided to prevent confusion. However, there’s no avoiding this in tooling, for example any time we want to give an informative error message or suggestion (linters, compilers/transpilers/interpreters, etc.), generate code from a template (doctest, formatters, refactoring tools, static/dynamic analysis, etc.). The harder it is to make tooling, the less tooling there will be; this affects all language users indirectly.

                                        At this point I also feel the need to point out the benefits of distinguishing between reading (determining a program’s structure) and parsing (determining a program’s language constructs). Lisps make this distinction, which makes tooling so easy that we can choose whether we prefer writing with delimiters or with indentation; we can also choose whether to use math notation, prefix notation or infix notation; or a mixture of all the above, and use simple tools to convert between them as desired.

                                        1. 3

                                          I ended up concluding that the fault is in the structured programming and that we don’t need indentation sensitive syntax, because we don’t need deeply nested structures that much either. The code can be written “1 block, 2 block, 3 block, “ so on…

                                          1. 2

                                            There’s a reason people adopted structured programming

                                          2. 1

                                            Braces and indentation is redundant information. A good thing about that is that if someone comes after you and adds an indentation bug, it will look wrong, and a compiler might catch that as “misleading indentation” (as does gcc).

                                            1. 2

                                              Not all forms of indentation bugs look wrong. Particularly the “this was supposed to be in the outer block” bug.

                                              1. 2

                                                This is why in Go you specify only the braces and you let your editor and gofmt manage indentation :-)

                                                1. 1

                                                  Well, running gofmt destroys the redundant information and any benefit with it :-(

                                                  Think of the indentation as the checksum of the brace placement: If they don’t match, you have an opportunity to find a potential bug!

                                                  • indentation = how it looks like it works (likely what the programmer intended)
                                                  • braces = how it actually works