This is a pretty genuinely confounding response, and I mean that with absolutely no offense intended. There is a tremendous amount of fighting between devs who prefer Go and Rust, and a tremendous amount of elitism as well, truly from both perspectives. Rust gained a reputation for elitism long before Go did; “Rust Evangelism Strike Force” was never meant to be pejorative, and “Rewrite it in Rust” was never meant to be a joke, but it became one anyways. It’s not hard to see why; Rust is genuinely novel in a way that few other programming languages are. It feels the most like the “future.”
But I still like Go a lot. I like Go because of how easy and simple it feels. There is definitely elitism over simplicity, but the elitism I’ve seen and even received from Rust and C++ programmers (…despite that I have been coding C++ forever and do have a few Rust projects as well…) has been pretty much the opposite: Go is too stupid and simple; real programmers need absurdly complex metaprogramming to make basic CLI tools or what have you. Now for what it’s worth, that has cooled down in many regards, and also, Rust is amazing and there’s nothing wrong with advanced metaprogramming. (It’s just another set of tradeoffs, after all. Unquestionably has its benefits.)
However, whereas people who have hated on Rust have often come to see it for what it is (an immensely cool, novel programming language,) Go has received the opposite treatment. People soured on it. Now everyone seems sure the GC latency (which of course is just about state of the art) is simply too much for most use cases. It’s seen adoption in all sorts of places and even been competitive with Rust software in performance, but it is commonly discussed as if Go is inherently obsolete because Rust is a better option in every way that matters. Bringing up Go in certain places often subjects you to ridicule, and I’m not joking. The memory ballast is a favorite among detractors to prove that the language is stupid and bad for production environments.
So when people do try to tout the benefits of Go, it’s routinely discredited and downplayed for some reason. It’s a nice language to use with a stellar standard library, nice tooling, and pretty good runtime performance.
This article doesn’t mention Rust (that I noticed) and Go is still being measured up to Rust in the comments. They both trade blows in different categories, but I truly believe that the fact that Go lacks the novelty of Rust with its borrow checker and language design has caused a lot of people to view it very negatively, and I think that is sad. People loved C for a lot of what it didn’t have. Go is a lot different than C, but for me, the sentiment is very much the same.
I think people see what they want to see. I like Go and Rust, but I find myself going back to Go for various reasons and it feels like every year it leads more and more people to ask for justification that they wouldn’t for other languages. It’s a little tiring.
> “Rust Evangelism Strike Force” was never meant to be pejorative, and “Rewrite it in Rust” was never meant to be a joke
Maybe it's just been such a long time, but my recollection was exactly that: both of these terms were invented by outsiders intending to denigrate the Rust community, and became jokes inside the community as a means of recuperating them.
Okay, I will mention one other thing here:
> This article doesn’t mention Rust (that I noticed) and Go is still being measured up to Rust in the comments.
I agree with this in 99.999% of threads, this happens all the time, and probably shouldn't. However, in this thread in particular with the way that the Go package management story developed, including all of the drama there, I don't think it's surprising that Rust/Cargo get mentioned in comparison.
I won’t comment on Rust Evangelism Strike Force too much; it seemed to be unironically used as a term of endearment at some point, but that could’ve been after its use as a pejorative. At this point, I can’t remember, and frankly, the world is probably better off forgetting.
I understand. In the earlier days of Go package management, it was pretty common for folks to compare it to Cargo. In retrospect, this was probably bad, but it did serve to highlight some pretty damning issues with Go at the time. But I feel they addressed the shortcomings significantly with Go modules, and now it has become much more a matter of taste.
I enjoy Go’s idea of trying to make source control the only source of truth, but I don’t think it’s as well-received as the more tried-and-true approach of Cargo and other centralized package repositories. I suppose time will tell.
To be clear, I have no issue with anyone who prefers Go. I was speaking about the core devs in particular. I would agree that the users of the language definitely go back and forth "trading blows".
Interesting and apologies for misunderstanding. I didn’t read the article as being elitist, though I can see how it reads as self-congratulatory to a degree. Maybe the matter-of-fact way that Go’s developers state its advantages comes off poorly compared to, for example, coming from the standpoint of trying to explain how they got to their current design based on the challenges. Personally, I find articles like this easier to read because they tend to be more terse when written this way versus some other approaches that are perhaps more humble.
Lovely comment. I share your sentiment. Go is truly hated on hacker news these days (and, if you're brave enough to venture there, reviled on r/programming).
I’ve read this article and debated it to the end of the planet. It’s not that the article is factually wrong, but it seems to be under the impression that there is an objective definition for “correct code.”
Of course, there’s degrees. To take an example, filenames. What is a filename? Is it a bag of bytes, a set of UNICODE codepoints, something more elaborate? No operating system agrees 100%. Go handles this by just simply not. It converts stuff to and from UTF-8 and if it doesn’t convert, you can’t use it. This is a limitation of Go programs that use Go’s built-in filesystem support (roughly all of them.)
That decision is a clear-cut simplification of reality. It can matter. However, the fact that it comes up so seldom is a reflection of reality: normally, you are totally able to make the concession that you only handle paths that are valid UTF-8 and nothing else. Go makes this concession on your behalf. It makes many such concessions, and it is documented, though not very well-known, because most developers don’t care. What most developers want is a language that makes sensible tradeoffs so that their programs can remain simple but still reasonable. In TYOOL 2022, I absolutely think it is reasonable that a program may impose valid UNICODE filenames as a requirement.
Rust handles it with OsStr, of course. Now OsStr is a good idea, but it pushes the decision for how to handle the problem further down. On one hand, this is great if you absolutely must handle ridiculous filenames that have essentially arbitrary bytes or old encodings in them, which, to be sure, is a real thing.
The file permissions stuff is similar. If Go is going to present a file permissions interface and then just fudge it, what’s the point of including it at all? Well, in my estimation, the point is that on POSIX systems, you can’t really avoid dealing with file permission bits. In most cases, when a Go program specifies mode bits, its doing so so that on POSIX, the program doesn’t write a file with permissions that don’t make sense, are unusable, or potentially even open up security issues. (You would not want user-uploaded data to go into a file with +x!) On Windows, it can usually be ignored, at least from the scope of the Go software. That’s, again, an opinionated choice. If I needed more granular control over permission, I would probably need more OS-specific code and interfaces anyways, something that is totally doable in Go.
So far Go is oversimplifying things in a very opinionated manner. And in fact, this means that some programs are difficult to write correctly in Go.
But, and here’s the kicker, I don’t usually want to write code that breaks the assumptions that Go makes and requires in its standard library. Even if I’m in Rust, if I want to write some utility code that deals with filenames, often times the string transformations I want to perform on the filename I will want to do in the space of valid UNICODE, because it’s simple and predictable. Even if all I want to do is append a suffix before the file extension, I still would prefer to work in valid UNICODE only. If I’m dealing with say, a broken Shift-JIS filename and want to append a suffix, even if I try to do the right thing and treat it as an ASCII compatible bag of bytes, I could wind up with an even more broken filename as a result, because the state of the filename before the suffix could corrupt the suffix.
The key difference is in perspective. “100% correct” is demonstrably unattainable. You can make more exact abstractions, but for sanity we make assumptions left and right that are “good enough.” You really shouldn’t use the user home directory or user profile directory of a given OS for much directly because it’s honestly a different directory with very different semantics per OS, yet plenty of Rust software (and Go software!) still does this anyways.
Meanwhile, while writing perfectly watertight code in Go is basically impossible, it’s also not a fair benchmark. Nothing does that. Rust is especially prone to stack overflows due to its lack of placement new, and it’s absolutely trivial to do this. Go doesn’t really have stack overflows at all, because it has a dynamically expanding stack. Cargo and its ecosystem has a problem with dependency hell; 200 nested dependencies to install a tool that counts lines of source code is a real thing that actually exists. Go’s ecosystem is definitely in better shape here, for reasons mentioned in the article that I wholeheartedly agree with. There are more things I could say that I don't like about Rust. I could possibly even fill an article about it, but I don't think that it's very productive. I think it's better to just acknowledge that most of these pain points are a direct result of the fact that any decision you make about language design and tooling will have knock-on effects down the ecosystem.
This article is also unfair in that it basically pins Go, a language which intentionally limits scope by taking these concessions, with Rust, a language that happily expands scope to try to cover more edge cases. Both choices are valid and offer different tradeoffs. However, there is a world of different programming languages, and Go is not the first one that implies limitations on filenames, for example. Hell, what happens if you write plain C code that tries to access broken Windows filenames? How much Win32 C code exists that doesn’t handle UNICODE or broken filenames? How many times have you tried to compile some code and had to move it to a directory without spaces in the filename because the program didn’t handle that?
Go is an opinionated language. If you don’t like its opinions, you won’t be happy with it. Orienting this as a correctness issue makes it seem like the Go developers made these tradeoffs haphazardly and without thought. I just flatly disagree.
But I still like Go a lot. I like Go because of how easy and simple it feels. There is definitely elitism over simplicity, but the elitism I’ve seen and even received from Rust and C++ programmers (…despite that I have been coding C++ forever and do have a few Rust projects as well…) has been pretty much the opposite: Go is too stupid and simple; real programmers need absurdly complex metaprogramming to make basic CLI tools or what have you. Now for what it’s worth, that has cooled down in many regards, and also, Rust is amazing and there’s nothing wrong with advanced metaprogramming. (It’s just another set of tradeoffs, after all. Unquestionably has its benefits.)
However, whereas people who have hated on Rust have often come to see it for what it is (an immensely cool, novel programming language,) Go has received the opposite treatment. People soured on it. Now everyone seems sure the GC latency (which of course is just about state of the art) is simply too much for most use cases. It’s seen adoption in all sorts of places and even been competitive with Rust software in performance, but it is commonly discussed as if Go is inherently obsolete because Rust is a better option in every way that matters. Bringing up Go in certain places often subjects you to ridicule, and I’m not joking. The memory ballast is a favorite among detractors to prove that the language is stupid and bad for production environments.
So when people do try to tout the benefits of Go, it’s routinely discredited and downplayed for some reason. It’s a nice language to use with a stellar standard library, nice tooling, and pretty good runtime performance.
This article doesn’t mention Rust (that I noticed) and Go is still being measured up to Rust in the comments. They both trade blows in different categories, but I truly believe that the fact that Go lacks the novelty of Rust with its borrow checker and language design has caused a lot of people to view it very negatively, and I think that is sad. People loved C for a lot of what it didn’t have. Go is a lot different than C, but for me, the sentiment is very much the same.
I think people see what they want to see. I like Go and Rust, but I find myself going back to Go for various reasons and it feels like every year it leads more and more people to ask for justification that they wouldn’t for other languages. It’s a little tiring.