1. 27
    Let's Give It a Go go natano.net
  1.  

  2. 14

    I think the only other occurence of long options with single-dash prefix I have ever seen is in X11 tools. Why break with the de-facto standard way of doing things?

    find(1) would also be a popular example, but I’m quite sure I have seen a few more.

    1. 4

      Oh yeah, I forgot about that one, even though I use it almost evey day. ;)

      1. 2

        Also another example I remembered would be qemu.

      2. 1

        and gcc

        1. 3

          That’s tricky, because most of gcc’s flags are of the form -[one letter key][rest of the word is the value], which is kind of another thing again?

      3. 7

        Go hit 1.0 eight years ago. Can we please stop circulating these thinkpieces written by people who have spent all of one weekend with the language that just whinge about how it’s not a clone of something else?

        the timestamp example is exceptionally contrived because in reality you would never call time.Parse with two string literals. If you are writing the string literal into the source, you already know the value of the timestamp; you’d never start with a string literal and then parse it with another string literal because you’re turning what can be a compile-time error into a runtime error; you would just construct the value directly with time.Date, which cannot give you an error. I have been programming Go professionally since 2012 and this has never once been a problem for me.

        the XML thing is a quagmire because XML itself is rife with redundancies and ambiguities. Try using an XML parser in any other statically typed language and compare them. They’re all a nightmare. Go sucks here but the alternatives suck more so I don’t understand why anyone would feel the need to belabor this point beyond using it to bring traffic to their blog.

        The Go grammar definition contains semicolons, but you don’t see them much in idiomatic Go code.

        The semicolon is a statement separator, every for loop delimits its statements with the semicolon for the same reason. Every if err := fn(); err != nil { invocation is a standard usage of the semicolon. So no, not really.

        Taking shots at javascript for semicolon insertion in (checks watch) 2020? Yawn.

        To me Go doesn’t really seem to be designed as a general purpose programming language

        how could you possibly conclude such a thing from this tiny example? did you try to use it for any other domain? Talk about that. What’s established does not come anywhere close to being sufficient evidence to support such a conclusion.

        Go also seems to suffer from ignorance towards well established patterns that are proven to work

        this is where I just, quite frankly, lose it. Without this comment I would not have bothered to respond to this piece.

        You can’t just hand waive and say they’re ignorant of “well established patterns” without naming which patterns specifically. I’m willing to bet for the majority of patterns you can name, somebody on the Go team has written publicly about how the Go team has thought about that problem. It will never cease to amaze me that the Go team can, for example, write what now must be hundreds of pages of explanations as to why generics aren’t there and people will still stand back and say “the Go team hasn’t thought about generics”. There are a lot of things that the Go team has thought about and intentionally decided to omit. They didn’t decide to do what you wanted them to do. You can talk about why you disagree with their conclusions but if you’re going to just make a blanket statement that they haven’t thought about it, you’re just making unsubstantiated accusations of incompetence.

        The Go team has made some very opinionated choices and some of those choices I don’t agree with. There are aspects of the language that I find absolutely irritating (the lack of sum types is particularly aggravating to me). Go is not a perfect tool. It has its problems. But to say that the Go team is ignorant is something that I will always stand up to oppose. The Go team is absolutely exemplary when it comes to explaining their design philosophy, their strategy, and design problems that are works in progress.

        the getopt thing does suck though lol

        1. 2

          I don’t understand where the hate is coming from. I used Go to write software and made some observations while doing so. Then I shared them with other people on a platform whose purpose is to share links. What’s wrong about that?

          Yes, the timestamp example is contrived. I did that to make a point that the format and the value to be parsed look the same.

          the XML thing is a quagmire because XML itself is rife with redundancies and ambiguities. Try using an XML parser in any other statically typed language and compare them. They’re all a nightmare. Go sucks here but the alternatives suck more so I don’t understand why anyone would feel the need to belabor this point beyond using it to bring traffic to their blog.

          I praised the XML parser in Go: “Parsing XML in Go is relatively easy, and I have to admit rather neat. Definitely more comfortable to use than Python’s ElementTree.” The personal attack was completely uncalled for.

          Go also seems to suffer from ignorance towards well established patterns that are proven to work

          this is where I just, quite frankly, lose it. Without this comment I would not have bothered to respond to this piece.

          Damn, I chose some unfortunate wording there… Let me repeat a comment here that I wrote in response to someone else complaining about the same issue:

          Yes, datetime parsing and flag handling is what I was refering to.

          Go is developed by smart people, I never assumed they are not aware of how timestamp formats look like in other languages. I assumed they did it differently anyway ignoring the established practices, that’s why i wrote ‘ignorance’. Maybe not the most fortunate wording, didn’t mean to offend.

          1. 4

            I had the same reaction to your blog post as scraps. On seeing your response and reflecting, I think it’s just a matter of being so tired of surface-level criticisms of Go that seem to sweep up the rankings on hacker news etc. Which is 100% not your fault; of course you’re entitled to write about your experiences.

            While your article was pretty balanced in pro/anti sentiments, the fact that it was sandwiched between a contrived and sarcastic example at the start, and closing remarks that used “ignorance” to mean “ignoring”, “disregarding”, or “choosing differently”, meant that my brain put your article into the “sigh, another one of these; why are they always so popular?” category :-)

            (fwiw, I agree with scraps that sum types are the biggest obvious hole in Go)

            1. 3

              this is exactly right.

        2. 7

          I’m returning to a go project at work and feel a little more sensitive to these comments (so take with a grain of salt).

          • Timestamp parsing - I never do timestamp parsing without looking at the documentation (Oracle’s vs Java’s vs C#‘s vs SQL Server vs Javascript), so i feel that Go’s formatting being based on a magical date is “quirky”, but you can easily do date formatting/parsing just by referring to the one magical date ( 01/02 03:04:05PM ’06 -0700 ) which seems pretty cheap for the large amount of flexibility.

          • XML - I’ve dealt with more of this than I’d like and ran into awkward parts when dealing with multiple namespaces (canonicalization is a pain) but for straightforward xml, Go is pretty delightful to deal with. I haven’t needed anything faster or more complicated.

          • Flags - Again, Go is fairly idiomatic (based upon very old-school Unix command line sensibilities), but the Flags package gets so much stuff absolutely correct (built in help, connects to custom object parsing, default values). I’ve never used it but I believe the Go community really likes Steve Francia’s cobra, if you want/need more complicated stuff.

          • The compiler is one of the things that has gotten more complicated (dealing with multiple modes for dynamic objects, etc), but everyone appreciates it being:

            • cross platform
            • fast
            • produces fairly fast code
            • debuggable

            and the Go team spends lots of time keeping those in mind.

          • Modules - My last usage of Go is actually before modules landed so I need to get caught up on them. I never really liked some of the awkwardness of GOPATH (especially since there were multiple tools that handled pinning versions).

          • The last comment is… interesting. I’m pretty confident that the Go team isn’t ignorant of “well established patterns that are proven to work”, but have strong (idiomatic) design opinions. I happen to like the design aesthetic of the language, but realize it’s not for everyone.

          1. 3

            I’m a bit curious about the magical date you mentioned, how does go deduce from that whether it is the 1st of february or the 2nd of january?

            1. 6

              It’s not that magical. It’s basically just the same as “classic” string parsing with strptime() and %Y and whatnot, but instead of %Y you use 2006, and instead of %d you use 01, etc.

              The idea is that instead of %Y-%m-%d you have a more human-readable 2006-01-02. It’s quite easy to memorize too, since 2006 is the year, and after that it just increases from high to low. Also see some examples from the docs.

              In other words, it’s a lot less magical than strptime(), IMHO. For example for this comment I looked up if it was %m or %M for day-of-month, and then it turns out it’s actually %d.

              1. 1

                The idea is that instead of %Y-%m-%d you have a more human-readable 2006-01-02.

                One can only imagine the ease-of-use if they had picked an order that was used in more than one country on this planet. Feels a bit like the usual jingoism.

                It’s quite easy to memorize too, since 2006 is the year, and after that it just increases from high to low.

                It’s timezone > year > second > minute > hour > day > month. There is nothing logical about it, except that it looks the way some American’s prefer to write their date.

                1. 1

                  I think the other part is that each portion has a different number (the month is always 01, the day is always 02, etc).

                  1. 1

                    Yes and that is ordered (“intuitively”) timezone > year > second > minute > hour > day > month.

              2. 4

                If you work with go dates regularly you end up memorizing the order pretty quickly.

                That said, I think it’d have been nice if they’d used the 13th December instead since 2006-12-13 is less ambiguous.

                Unfortunately, that would’ve meant not having a nice way to make _2 indicate no leading zero. No easy tradeoffs.

                1. 2

                  You have a better memory than me. I’ve been with Go since 1.3 and I still have to look up the documentation every time. I think that if they wanted to do dates like this, they should have gone with the ISO format 2000-01-02 03:04:05. That would have been way more intuitive to way more people.

                  1. 1

                    It’s less the quality of my memory, and more that I was working with date parsing on a regular basis for a couple of weeks. If you don’t do it often there’s no way you would memorize it.

                2. 2

                  It is a bit American centric, but the date in documentation is also written

                  Mon Jan 2 15:04:05 MST 2006

                3. 3

                  Thank you for the feedback!

                  Timestamp parsing - I never do timestamp parsing without looking at the documentation.

                  To me %m just seems more intuitive than 01 for referencing the month, because ‘m’ is a mnemonic for month, but ‘01’ doesn’t tell me much. One thing it does tell me though, is that the number to be formatted is 0-padded, which is admittedly a nice touch.

                  […] the Flags package gets so much stuff absolutely correct […]

                  Yes, agreed. I think the API is great, I just criticized the perceived quirkiness of the resulting command interface.

                  Go is not a bad language (far from it), I just believe some of the bold design decisions to not be the best choice.

                4. 7

                  Wow, the time parsing API is …. something. It’s pretty clever! But you really have to really not want to just use format params in order to end up writing such an API.

                  I wonder how much other fun APIs are in go, I kinda assumed that it would have some pretty boring APIs on account of its core language not providing much flexibility.

                  1. 10

                    Speaking specifically about the flag anomaly, I much prefer Go’s package because it removes ambiguity. In a getopt(1) program, when I see -abc, this could mean two separate things: either there are three flags -a -b -c written in a shortened form, or there is a single flag -a which takes a string argument bc. Go’s flag removes this ambiguity entirely.

                    1. 8

                      It doesn’t, because you as an end user don’t know if the program is written in Go, or if the author wrote their own argument handling because they didn’t like the flag package.

                      1. 2

                        Still, clarity is something to strive towards as we develop software.

                        There are other reasons I prefer flag as well. For example, it is possible to provide boolean flags with true defaults, and to disable them with -name=false. This is in contrast to getopt(1)-style flag handling where individual character flags can only be toggled on.

                        1. 1

                          I personally am a fan of having both — short and long options — around.

                          I use the short options when typing in a shell, because it’s convenient. I also usually bunch together multiple options, e.g. ls -ltr, just because of typing efficiency. (I also type python3 -mvenv env without space between the option and the argument, sue me!) For shell scripts on the other hand long options might make code more readable/self-explanatory, especially if co-workers also have to maintain it.

                          That’s why I like having the single-dash prefix reserved for short options and double-dash for long options, because both variants have their place.

                    2. 6

                      Note that both -flag and --flag work with Go’s flag package, although the single - is more conventional.

                      1. 3

                        People will use whatever -h tells them is available. And it shows the single dash options.

                        1. 1

                          Interesting, I didn’t know that. Thanks for pointing it out!

                        2. 5

                          The time example is kind of silly, usually one argument is a variable, the other is a constant format string so you can easily deduce which is the format string.

                          1. 1

                            The ‘silliness’ is exactly why I picked that example. :) I did that to make a point that the format and the value to be parsed look the same.

                            1. 1

                              That’s the GP’s point: in real world code, they don’t! This is typical code:

                              time.Parse(ExpectedFormat, value)

                              e.g. here’s code from my own project:

                              https://github.com/contribsys/faktory/blob/master/util/util.go#L144

                          2. 4

                            I think the only other occurence of long options with single-dash prefix I have ever seen is in X11 tools.

                            Also OCaml: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Arg.html

                            Incidentally, OCaml is another fast compiler which outputs fairly efficient code.

                            1. 6

                              I thought this was a really good, terse article. I apologize in advance that this comment only focuses on disagreements (I find disagreements more interesting, but people often misinterpret them as defensiveness or something; I need to find a better way to communicate).

                              To me Go doesn’t really seem to be designed as a general purpose programming language, but rather targeted towards a specific niche (although a big one at that) — web services. All of the necessary tools are there: Template rendering, parsing common data formats like XML and JSON, HTTP client and server implementations, hash algorithms, encryption, rudimentary SQL support, and all text is unicode.

                              What’s your standard for a general purpose programming language? Does it have to run on bare metal? Or have a GUI toolkit and/or scientific computing modules in the standard library?

                              Go seems pretty vanilla to me. It’s used for a lot of web service things, but also for a lot of cloud/systems-y things like Docker, Kubernetes, and just about everything Hashicorp has touched since Vagrant. Further, there’s no GUI toolkit, but that’s probably because building a cross-platform (desktop) GUI toolkit worth using is a monumental task, there still isn’t a clear “right way” to do this (a lot of movement in this space), and it’s not clear whether native desktop apps are even the future. Last I checked, Go’s scientific computing story was actually moving right along, but I also haven’t checked in in a few years.

                              To pick a couple more nits, “text” doesn’t have to be unicode (you can put anything in a string), but string literals are always encoded as utf-8. Also, Go doesn’t have anything in the std lib for authentication, which is more important for modern web services than things like templating or XML.

                              1. 2

                                Glad you liked the article, and thank you for the insights!

                              2. 5

                                the compiler presents those warnings as errors, meaning the build stops and you don’t get a runnable binary. That’s quite annoying when developing or debugging a program: commenting out a block of code, and now suddenly you have to modify much more code because an import is not used anymore

                                Hook your editor up to goimports or gopls.

                                1. 1

                                  Yes, that would alleviate the problem. I just hoped it wouldn’t be necessary, because I like to avoid modifying my editor for a specific programming language. (I run vim with ctrlp and vimwiki being the only plugins.)

                                  1. 1

                                    Language-server protocols are a huge boost to code comprehension, IMO. Well worth the extra configuration effort.

                                2. 3

                                  One of the virtues of strftime, probably not obvious to English speakers, is that strftime works with your machine’s locale settings. If my computer is in English or Spanish %c works as expected. Go completely breaks that feature.

                                  1. 7

                                    Pretty poorly informed piece. Hilarious that it ends with “Go also seems to suffer from ignorance towards well established patterns that are proven to work” and then fails to provide a single example.

                                    1. 4

                                      The datetime parsing and command line flag handling mentioned in the articles are the examples.

                                      1. 5

                                        They’re not examples of ignorance. The Go team was well aware of how date parsing has been done historically but decided to try something more intuitive. The way they wrote the example was carefully chosen to make it look confusing. See https://golangcode.com/parsing-dates/ for how this is usually used.

                                        1. 4

                                          I don’t have enough experience with Go to have an opinion about the specifics I just wanted to clarify what seemed like the intentions of the author to me. I get that you don’t agree with the examples but I think that’s something entirely different from claiming that they aren’t there.

                                          1. 2

                                            Yes, datetime parsing and flag handling is what I was refering to.

                                            Go is developed by smart people, I never assumed they are not aware of how timestamp formats look like in other languages. I assumed they did it differently anyway ignoring the established practices, that’s why i wrote ‘ignorance’. Maybe not the most fortunate wording, didn’t mean to offend.

                                            1. 0

                                              That’s, uh, not what “ignorance” means…

                                    2. 2

                                      it took me too long to find Go’s flag package. Made cl arg parsing so much easier

                                      1. 4

                                        I found github.com/urfave/cli is more convenient to use than builtin flag package.

                                        1. 3

                                          They have a nice entry in GoByExample: https://gobyexample.com/command-line-flags

                                          1. 1

                                            love that site - that’s actually where I discovered flags

                                          2. 1

                                            What did you do before?

                                            1. 2

                                              i basically would try to implement arg parsing myself by treating an array of arguments (i think os.Argv… could be wrong) as a stack… I would pop off from the front and compare to check flags, assign optional values, etc.

                                              I also have used someone’s getopt package for go: https://github.com/mattn/go-getopt

                                          3. 1

                                            go presents those warnings as errors because how many times have you opened a java project and seen 97 lines of unused imports? No one fixes them because they are just annoying but don’t actually prevent you doing anything

                                            1. 1

                                              I have a couple issues with this article. Most notably, the way the author portrayed the way time.Parse works.

                                              In real life, this would actually look something more like:

                                              currentTime, err := time.Parse("2006-01-02 15:04:05", timestamp)
                                              
                                              // or, if dealing with some form of standardized timestamp
                                              
                                              currentTime, err := time.Parse(time.RFC3339, timestamp)
                                              

                                              I can understand the weird order of arguments, but it’s not quite as confusing if your vars are named correctly. In my opinion, this makes dates and times much easier to parse and deal with rather than looking up whether I should be using %H or %h in man strptime

                                              The compiler is another story. While I do agree that whining about what seem to be just “tidiness” issues in the code is annoying in the development process, I think the reasoning behind throwing an error when you have a dangling import or unused variable boils down to compile-time optimization. If the compiler doesn’t need to import something that you’re not using, you can save time and speed up the compilation process. I’m sure it’s not a big change with one import, but what about 50? That could seriously change things. All that being said, I still think this is an improvement that can be made within the toolchain of the language, but I believe it’s the job of gofmt or gopls to handle manipulation of your code before it gets to the compiler to avoid these errors. Something where it would automatically comment out an import when you comment out code that uses it, and removing the import if you delete the code that uses it. I would love to see something like this in Go, it would definitely improve the development experience.

                                              The rest of the article is opinions, and the author is certainly entitled to them, so those aren’t what I have an issue with.

                                              1. 2

                                                Of course you wouldn’t parse a string constant in real code, except maybe in a unit test for the time.Parse() function itself. ;) All I did is choose a humorous way of showing that the format string looks similar to the timestamps it is supposed to parse. I don’t think the order of arguments is a concern.

                                                Ad compiler: I believe for development a quick debug cycle between writing code and running the binary to try it is quite important, that’s why I find those errors annoying. I still think being notified about unused code in an automated way is great by itself. When writing Python code I regularly run pyflakes to find issues like that, but on my schedule, when I deem it useful (usually before committing a diff). That’s what I meant with the tool working for the programmer, not the other way around.

                                                Hope this clears things up.