1. 59
  1.  

  2. 29

    One thing I don’t think I’m ever going to get is how much Go does in comments. In my mind, comments are a way to communicate something to other humans, or, sometimes, a way to communicate something to some external tool (such as a documentation generator). However, in Go, you configure whether the file should be built in comments, you write C code in comments with CGo, you write shell commands for code generation in comments, and, with 1.16, you embed data into your binary using comments.

    I’m all for a kind of extensible meta language; a way to have commands in the code which the compiler proper will skip, but which official tooling might interpret. Something like a #pragma. But… in my mind, the official language toolchain shouldn’t extensively parse my comments.

    On the positive side though, I think what embed does is really cool. More languages should have a way to embed arbitrary data into the binary (without hacks).

    1. 17

      If it helps, you can consider the string //go: to be equivalent to the string #pragma and not think of it as a comment. Reusing the comment syntax has the advantage that parsers/formatters don’t have to worry about parsing anything other than comments. Much like how a shebang (#!/usr/bin/env bash) happens to be a comment in a bunch of scripting languages.

      1. 17

        Yea, if it was only that, I wouldn’t have been too worried. However, you also have a case where a comment changes the semantics of the following import after the comment. The whole thing seems like a giant hack to me; like “changing the grammar is too much work, so we’ll just make the tooling parse your comments so we don’t have to change the compiler”. I’m not saying that’s how the process is; I’m saying that’s how it feels as an observer.

        I would’ve probably done something like C, where lines starting with # are obviously going to be interpreted differently from other lines. The compiler could ignore all lines starting with #, so that the tooling could add new directives in a backwards-compatible way, and parsers/formatters could largely ignore them. It just would’ve been a structured thing instead of essentially parsing prose.

        1. 10

          The whole thing seems like a giant hack to me; like “changing the grammar is too much work, so we’ll just (…)

          This is how I feel about imports as strings. I see no good reason why we need quotation marks around the import paths in Go, it should be obvious for a parser how to deal with a path there. In general the Go syntax is… inconsistent at best.

          1. 3

            I see no good reason why we need quotation marks around the import paths in Go

            This is a guess, but it may be to make plumbing easier in Plan 9/Acme. Syntax like <something> and "something" is easier to match than just something.

            1. 1

              I think the comment you’re replying to is arguing that it’s not just "something" vs. something, but import "something" vs. import something.

              1. 3

                Yeah, I know, but multiple imports still need quotation marks to be plumbable:

                import (
                    "path/to/package1"
                    "path/to/package2"
                )
                

                works, whereas

                import (
                    path/to/package1
                    path/to/package2
                )
                

                wouldn’t.

                1. 2

                  Not sure why that would be the case. the plumber gets the whole string either way, expanded out to the surrounding whitespace if there’s no selection.

                  1. 4

                    But the plumber has to know somehow that it is a Go import path. The quotation mark syntax in Go (and C) makes that clear.

                    For example, should test, without quotes, really be treated as a Go/C import path? Wouldn’t that be too broad a rule?

                    1. 1

                      The plumber also gets a bunch of context, like the place you plumbed from. It should use that.

            2. 3

              I thought the same at first, but it’s simpler for the lexer/tokenizer to not have to know what mode it’s in. It’ll (presumably) just output a STRING token, and it’s only the parser that has to know that it’s in an import directive. Go is partly about keeping parsing (and lexing) simple and fast.

            3. 6

              It’s not my most favourite syntax either, but using #pragma or //go: seems like a really minor issue. I’m not sure what the motivation was for choosing //go: over # or #pragma.

              a case where a comment changes the semantics of the following import after the comment

              I assume you mean package foo // import "bar" type comments? That one, in particular, was a mistake IMO. But also kind of obsoleted by modules, and not really related to //go: directives.

              1. 1

                I don’t know what package foo // import "bar" does. Could you elaborate on it?

                I was talking mostly about CGo, where you have a giant comment with a mix of C code and #cgo pseudo-directives followed by a line with import "C", where the comment (minus the #cgo lines) is compiled by a C compiler and linked with the binary.

                1. 3

                  It enforces that the package is imported as bar; often used for “vanity paths”; e.g. lobste.rs/mypkg instead of github.com/lobsters/mypkg. This prevents some problem where one dependency might use the lobste.rs path, and the other the github.com path. It’s a bit of a hack, and you can do the same with a go.mod file now.

                  cgo is kind of a tricky beast, yeah; but also fairly rare. And since you can write any C code in that comment, I’m also not sure how else to do it? Overall, it seems to work fairly well and in the grand scheme of things, it seems like a fairly minor issue to me.

          2. 37

            But it’s a great way to pretend that it’s a small language with few reserved words.

            1. 7

              Even with the comment syntax, Go has fewer reserved words than C.

              1. 7

                While I agree with your comment, it’s a non sequitur. Having fewer reserved words and being a smaller language are two different things. LISP has 0 reserved words, therefore it must be the smallest language, right?

                1. 4

                  Go is still a small language.

            2. 3

              This is the long-standing rationale for not having comments in JSON, and I think it stands the test of time (and complaints of programmers).

              1. 16

                This was just paternalistic nonsense on Crockford’s part. While I don’t really understand the Go author’s decision to use comments for pragmas, I would never in my life give up all comments to put a stop to it. An absolute textbook example of cutting off one’s nose to spite one’s face.

                1. 16

                  I think it makes perfect sense for JSON’s intended usage as a data interchange format with good interoperability between all sorts of different environments. Extensions have made this much harder than it needs to be on more than a few occasions in the past.

                  Now, if you want to use JSON for your config files then sure, it’s annoying. But that wasn’t the intended usage. If you’re driving a square peg through a round hole then you shouldn’t really complain about the peg shape but get a different peg instead.

                  1. 7

                    I still don’t buy it. If we’re considering the intended usage, one of the goals that gets thrown around is that it is “easy for humans to read and write” – just as long as they never need to convey something to another human being in the form of a comment!

                    There are so many other under-specified parts of JSON, like what to do with large integers, or what happens when a document contains duplicate keys. It is extremely frustrating that comments were intentionally and unnecessarily stripped out, while the hard problems were apparently just ignored.

                    1. 8

                      HTTP or SMTP are easy for humans to read and write, and don’t have comments either because in the intended usage space it’s not really needed. Like those data formats, JSON is primarily intended to send text from one program to the other, and the “easy for humans to read and write” is more as a debugging and testing aid than anything else.

                      There are so many other under-specified parts of JSON, like what to do with large integers, or what happens when a document contains duplicate keys. It is extremely frustrating that comments were intentionally and unnecessarily stripped out, while the hard problems were apparently just ignored.

                      Sure, it could be improved, maybe, but as you mention these are not easy things to define in a compatible way since different languages deal with these things in different ways. But I don’t think that’s a good reason to introduce more interoperability issues.

              2. 2

                The comment syntax is mainly used together with cgo. Including a header instead of inlining C makes it feel less hacky and allows for syntax highlighting of the C code for a larger range of editors: // #include "project.h".

                1. 2

                  IIRC there was discussion of adding pragma syntax, but it was decided that it’s not worth it to add yet another syntax, since there already existed comment-based pragmas that would have to be kept because of the go 1 compat promise.

                2. 13

                  This release is a big deal for apps running in containers. It’s complicated to explain and I’m on mobile, but previously memory was lazily reclaimed by the OS, leading to containers being killed for exceeding memory limits. This definitely affected borg jobs at Google and presumably k8s.

                  Now the kernel will eagerly reclaim that memory, allowing the container to stay within memory limits more easily.

                  1. 3

                    And they also cleaned up how you read memory usage. 1.16 is a really nice release, improving a lot of small things.

                  2. 6

                    What a happy coincidence, this was released minutes after I finished my presentation about Go 1.16 at our local Go meetup.

                    1. 6

                      Can’t wait for Generics and I don’t think I am ever going back to a JVM based language!

                      1. 2

                        Maybe go will be worth another look after generics. I guess it should make implementing a sequence/stream API more feasible. Although I suspect the performance would suck, go probably can’t optimize the virtual function calls as much as a JIT can.
                        Coming from a JVM background, and having recently written a CLI app with go, I found the experience extremely painful, and I don’t quite understand why one would give up a higher level language to work with go for non-trivial applications.
                        Being able to easily build and cross compile native binaries is a great feature, especially for CLI’s, but if running a JVM isn’t a major constraint, I’d take any major JVM language over go.

                        1. 2

                          This kind of reflects my views about Go as well. I think once you are out of “simplicity” dogma, you quickly realize how messy the code gets with interface{} casts everywhere. I use generics on daily base! Even a basic cache requires generic support. I don’t want to litter my code with castings and ifs when there exists a decent solution to do all of the manual undertaking for you. That is what compilers were invented for rather than just generating plain code. You can obviously ignore them if you don’t need them; but I not having them is a big pain in the a**.

                          1. 7

                            you quickly realize how messy the code gets with interface{} casts everywhere.

                            It should essentially never happen that you use interface{} in day-to-day code. If you’re having that experience, I can understand why you’d be frustrated! You’re essentially fighting the language.

                            interface{} and package reflect are tools of last resort that really only need to be used in library code.

                            1. 1

                              Please feel free to attach a reusable LRU cache solution. A pretty common thing to do in any production grade app is to use a basic cache ranging all the way from caching addresses to deserialized objects. I am pretty sure you will have the same hacky if casting check and use solution.

                              1. 1

                                Please feel free to attach a reusable LRU cache solution. A pretty common thing to do in any production grade app is to use a basic cache ranging all the way from caching addresses to deserialized objects. I am pretty sure you will have the same hacky if casting check and use solution.

                                It’s not necessary for the LRU cache you write for your application to be reusable. It only needs to solve the needs of your application, which, by definition, deals with a bounded set of types, typically just one.

                                If your reaction to this is “But that’s stupid and of course I’m going to write a generic data structure…” then this is kind of exactly what I mean when I say that you’re fighting the language.

                              2. 1

                                Please feel free to attach a reusable LRU cache solution. A pretty common thing to do in any production grade app is to use a basic cache ranging all the way from caching addresses to deserialized objects. I am pretty sure you will have the same hacky if casting check and use solution.

                          2. 1

                            Two more releases, likely :)

                            I’m curious to see how the generics will work out in practice. But I do look forward to having a sane assert.Equal().

                          3. 1

                            I fail to see the use for Go for non-enterprise projects. It doesn’t seem to offer anything interesting compared to languages I already know (like C) apart from goroutines. I would love to be proved otherwise, though.

                            1. 11

                              I like using go for (personal) server applications, because it has a comprehensive and well-designed standard library, that generate static binaries that can be easily copied around. With the new embed directive, this should make it even easier. I think Go doesn’t want to be interesting, it wants to be convenient, and that is certainly something it manages.

                              1. 4

                                I love to use Go for personal projects because it costs nothing to host it. I am talking about resources consumption. It fits on many “free plan” VMs, where Java would not.

                              2. 2

                                Personally, I just find it easy to write and understand and plus I enjoy the syntax.
                                When most people have a rough idea of something they want to make they do up a prototype in Python, but I usually do the same in Go just because I enjoy writing it.

                                1. 1

                                  Compared to C for private and non enterprise projects Go offers:

                                  • No requirement for header files
                                  • Sometimes less verbosity
                                  • Nicer Errors
                                  • Faster build times

                                  While Go has good tooling C might still have more.