560 comments

[ 3.3 ms ] story [ 347 ms ] thread
What's up with the anti-Golang shitposts lately? I liked fasterthanlime better when he didn't just sound like a card-carrying Rust zealot. This isn't even about the practicalities of his argument really; optics matter, and it's especially bad since the Rust community used to be known for its politeness and always being fair to other language communities.
Just a small reminder: fasterthanlime is not the Rust community
The last time his "I want off" article was reposted[0], the comments were pretty rough, ranging from ad-hom attacks to (at best) misunderstandings of the arguments he was making.

I see this article being an address to these criticisms (which are not limited to this forum, I've seen similar arguments on twitter, etc.).

Pointing out shortcomings isn't really impolite or unfair. The author specifically mentioned shortcomings of Rust as well.

[0]: https://news.ycombinator.com/item?id=31191700

Pointing out shortcomings isn't impolite - writing that Go wasn't designed, but happened by accident is however (IMHO).
Especially since it was designed by computer science luminaries who are almost certainly better programmers/engineers than the author of this blog.

It's also more accurate to say that Rust wasn't designed / was an accident since it was technically a side project of one guy at Mozilla.

Both languages were designed by probably better programmers than most in this thread. For that matter, the vast majority of successful programming languages surely were. I'm utterly lost at how that relates to anything.

One can plainly be a good programmer and yet create a bad language. I'm sure you are well-informed enough to analyse his argument on its merits, even if it were written by a gang of monkeys with typewriters.

> writing that Go wasn't designed, but happened by accident is however [impolite]

That's one of the most mild and inoffensive criticisms I've ever read on the internet. You can't seriously be indignant about that.

The truth cannot be impolite.
> The last time his "I want off" article was reposted[0]

Of note: the last time in question was yesterday, the flagging and ad-hominems pretty obviously made lime's cupeth runneth over.

> the Rust community used to be known for its politeness and always being fair to other language communities

I have no particular affinity for Go or Rust. As an outsider this is not how I’ve ever perceived the Rust community, because the most present and visible parts of the Rust community were people showing up and complaining that Project X didn’t use their preferred silver bullet

Also honestly it's very toxic to anybody right of center. It's the type that says "we're so accepting" when really they only are of certain stuff. Lots of pronoun people and making the mascot "non binary" is needlessly shoving their ideology down people's throat. Not a problem in the U.S. because it fits with the corporate woke ideology but sure as hell gonna be if they want more worldwide community.

It's also way too hugboxxy and tbh that feels just as toxic some times as the alternative. Positivity to the point where it's obviously fake and forced and insincere.

Edit: howinteresting I can't reply to your comment but you are proving my point. At least you people are being more honest that it is intended to exclude a bunch of people.

As someone who both loves the Rust language and is very right of center, I've never found politics to pose much of a problem for the Rust community in practice. Yes there is occasional virtue signalling here and there but people don't let it get in the way of making programs that work.
Yeah, as someone who's gay and left-wing but equally irritated by the 'virtue signalling' stuff (my ideology is basically r/stupidpol), I don't find the Rust community too bad.

(FWIW, I appreciate your open-mindedness. I think that's the main thing I find objectionable on (parts of) both sides of the aisle: an inability to regard those who disagree as fundamentally well-intentioned human beings who happen to hold different beliefs.)

"pronoun people"

What, you cant handle queer people existing?

I know many trans people who use nonstandard pronouns like xe, ze or it.
Sorry, that's true, I didn't mean that literally no trans people (or gay people, black people, etc) use non-standard pronouns. I meant that it has nothing to do with their being gay or trans. Certainly some people may happen to be trans and also happen to use those pronouns.
I hope they are not expecting normal people to use these silly words.
There's still a lot of people out there who consider 'they/them' to be nonstandard when used for a specific person (as opposed to 'they/them' as a replacement for the generic 'he'; almost everybody opposed to that has come around or died).
Yeah, I should have clarified that I don’t consider that non-standard. Well, it’s semi-standard, I suppose. But yeah, I had in mind the ones more like ‘xe’ and ‘xer’.
> Their comment is about the (almost universally straight) people who demand to be called 'xe' or 'qwerty' or whatever.

The vast majority of people I’ve seen using neopronouns, or “it” or “they” pronouns (either exclusively or alternatively with classical gendered pronouns, e.g., “she/they”) have nonbinary gender identity or agender identity, and the vast majority of the exceptions are trans, and all the rest (i.e., the cisgender ones) I’ve encountered are one of bisexual, pansexual, asexual, or same-gender attracted, usually also with gender non-conforming presentation.

I have yet to encounter a cisgender heterosexual with nontraditional pronouns for their gender, though I am sure there are some somewhere doing it.

> The vast majority of people I’ve seen using neopronouns, or “it” or “they” pronouns (either exclusively or alternatively with classical gendered pronouns, e.g., “she/they”) have nonbinary gender identity or agender identity, and the vast majority of the exceptions are trans, and all the rest (i.e., the cisgender ones) I’ve encountered are one of bisexual, pansexual, asexual, or same-gender attracted, usually also with gender non-conforming presentation.

Yes, I'm talking about sexuality, not gender. Most of the people I know, and/or have met, who identify as 'xe' and suchlike, are straight and usually cis (in the sense of 'not actually trans' - they do often have 'gender identities' like 'genderqueer' which amount to 'I wear heels sometimes').

It's predominantly - in my experience - straight people who covet the counter-cultural aspect of being 'queer', but who face the small problem of not actually being gay or trans or anything else, which is easily remedied by adopting one of those slightly-meaningless 'gender identities' which uniformly amount to 'I'm a teeny bit [masc/femme] sometimes'.

(I literally had a conversation with someone once who argued that watching porn didn't mean they weren't asexual. They also happened to be in a long marriage with a husband they no longer slept with, though they once had. It took all my strength not to say "lady, you're not asexual or queer, you're just a bored housewife in a dead marriage".)

From the outside the Rust community seems so defensive about Go that it makes me very reluctant to dive deeper into Rust.
I use both & like both. Ignore the noise!
Yeah, same. They’re both nice languages, they both have great tooling, and they both have areas where they shine. I don’t see them as competitors really, but “You can also implement X in Y” is a fairly useless statement, of course you can.

I’m glad we have as many languages options as we do, and I enjoy writing a variety of languages for a variety of different projects. Sure, I have moments where I think “ugh why can’t I do X in language Y” or “C is cleaner in Y” etc etc.

I’ve found helpful people, critics, and fanatics in every language community. Don’t let that dissuade you from learning Rust (or Go, or …)

One person is not the community
I might not agree with fasterthanlime's opinion on Go (9/10 times I would opt to use Go over Rust), but calling this post a "shitpost" is unnecessarily dismissive. The post, like his previous post on Go, contain well thought out points that add to the discussion at the very least. Also I like his sense of humour :)

Edit: though, I suppose saying Go is not designed is also equally unnecessarily dismissive and hyperbolic.

Well-thought out, how? It's flogging a dead horse in a transparent, deliberate attempt to create controversy and flamebait. That's a shitpost pretty much by definition.
I don't think it's obvious this was done in bad faith, even if the author is at times flippant.
> Portland Oregon, the capital of grunge, coffee, poor weather and whiteness

it's kinda a shitpost

It's sarcasm, dumb humor - not trying to be inflammatory, or provocative - i.e. not shitposting.

And let's face it, Portland kinda takes itself too seriously.

I moved from Austin TEXAS to Portland to get away from the heat and forced conservitism. I also moved to Portland for the weather (cool and wet vs hot as hell and dry). I don't have to use my air conditioner!

As for Portland taking itself too seriously, are you serious? Portland has so many quirky things that the conservative states don't have(much less putting walls up and making some people, making 2nd class citizens ((yes, voting rights)), and you say Portland is too serious? Good luck with that gaslight.

They're funny(ish) asides which is pretty normal for lime.
I'm not complaining. I get the joke. I'll leave this for the Seattleites to argue.
yeah the actual titleholder to those is seattle
Calling a well documented blog post, even one you disagree with, a "shitpost" should be an embarrassment to you.

Guy makes a blog post about Go a few years ago. It gets posted here time and time again, not of his doing. A bunch of people challenge his premises, so he makes another post diving deeper into his arguments.

So what?

What's up with the literal hundreds of "Golang is amazing" posts this site has had? Is someone attempting to express dissent clearly that much of a bother?

But he doesn't dive deeper! If anything, he's more shallow. This just doesn't read like an honest appraisal of Go's pros and cons to me, he already has his mind set from the beginning (ok, we knew that two years ago already) and is just heaping on invectives: "one really good bit does not a platform make", "Evidently, the Go team didn't want to design a language", "Go is not adequate for production services unless your shop is literally made up of Go experts (Tailscale) or you have infinite money to spend on engineering costs (Google)" etc. etc.

What makes me angry about all this Go-bashing is that it might influence decision makers against moving from things like PHP or Node to Go - which I think would be an improvement, no matter how many flaws Go may or may not have.

> What makes me angry about all this Go-bashing

It's just a language! Take it easy.

The guy is not "heaping on invectives" - he's not criticizing you or someone you care about. He's pointing out some flaws in a language in a sarcastic way.

I would consider "Evidently, the Go team didn't want to design a language" to be at least borderline invective. From dictionary.com, definition 3: "an insulting or abusive word or expression". Yeah, that's pretty clearly insulting.
Oh just some sarcasm:

"Mom smokes, so it's probably okay"

"I remember fondly the time an audience member asked the Go team "why did you choose to ignore any research about type systems since the 1970s"? (Emphasis his, not mine)

"It doesn't matter who points out that "maybe we shouldn't hit ourselves in the head with a rake repeatedly""

"Or you can be horrified, as you realize that those complex problems only exist because Go is being used."

"you adopted a language that happened by accident" (a direct criticism at Go users)

"Evidently, the Go team didn't want to design a language."

"Because it needed to be familiar to "Googlers, fresh out of school, who probably learned some Java/C/C++/Python" (Rob Pike, Lang NEXT 2014), it borrowed from all of these."

I just have up here. Do you really think a production conversation can start from this? ESR has flamed less haughtily.

It only hurts, because it is true.
Oh just some sarcasm:

"Mom smokes, so it's probably okay"

"I remember fondly the time an audience member asked the Go team "why did you choose to ignore any research about type systems since the 1970s"? (Emphasis his, not mine)

"It doesn't matter who points out that "maybe we shouldn't hit ourselves in the head with a rake repeatedly""

"Or you can be horrified, as you realize that those complex problems only exist because Go is being used."

"you adopted a language that happened by accident" (a direct criticism at Go users)

"Evidently, the Go team didn't want to design a language."

"Because it needed to be familiar to "Googlers, fresh out of school, who probably learned some Java/C/C++/Python" (Rob Pike, Lang NEXT 2014), it borrowed from all of these."

I just gave up here. Do you really think a production conversation can start from this? ESR has flamed less haughtily.

I'd choose Node or PHP over Go for a greenfield project. (Although I can't think of a case where I'd choose them over Python.) All of those languages at least give me an FFI escape hatch in case I need it that isn't absolutely horrendous, both from a dev experience standpoint and a performance standpoint.
Yeah, preach. I wrote Go professionally for a couple of years, and I write Python now (I know, I know, but they pay me a ridiculous amount to do it). I would choose almost anything, including JS, over Go. It's a good language if you need to write highly concurrent high-level code with low-skill devs, but not for much else, and even then it requires an inordinate amount of menial boilerplate work to get simple stuff done. Having said that, I would still choose it – indeed anything - over Python.
Reminder that I'm not part of /any/ Rust teams, not part of the Rust foundation, etc. etc. My site is my space, and it is specifically designed to let me post my point of view without having to bear ( ) the responsibility of speaking for entire communities at once.

It's important for individuals to be able to do that, and it's on everyone else to make the distinction.

Thanks for your article. I hope you can ignore all the vitriol. It's embarrassing to see what I thought was a generally intelligent community having a collective tantrum because someone was mean about its favourite toy.
how boring? Don't wanna use Go? Use something else. What's the point? Invest your time on questioning your knowledge and improving it instead of this.
The point of these articles and other opinion-making (such as right here on HN) is that we don’t choose tools. We are given the popular tools. They are popular because other developers chose them at the companies were we work. And they chose them because they thought they would be suitable for the purpose.

So if you want to do everything in your power to prevent a tool you think is terrible from being more popular - you can do very little apart from writing opinion in blogs or forums, improving the tool, or provide better alternatives.

Shitting on a technology might seem like the least noble of the 3, but it’s likely quite time-efficient compared to the other two. It’s certainly not useless.

Why should I care if Go/Rust/anything else becomes popular? I don't expect that if I don't "fight" against a language I'll be forced to use it in 2 years: there will be space for different techs, tools and so on.

I can agree with you if we talk about "tools" that attacks our privacy, our rights and our freedom: spend you time convincing people to abandon facebook or something similar and you'll do something good.

But in this case, it doesn't change much, imho.

> I don't expect that if I don't "fight" against a language I'll be forced to use it

I didn’t used to worry about this until it started happening to the sharp, experienced Scala/Java team I’m on by preference. Other teams are now deploying half-finished platforms on which only Go is supported fully, or sometimes at all.

> Go's confusion between "type aliases" and "newtypes". The only way to make a newtype in go is to make a separate package with an opaque type and use interfaces for indirection, which is costly and awkward.

It's very unclear what this is supposed to mean. 'type Foo int' in Go creates a new 'Foo' type that can't be used as an int without casting (a̶l̶t̶h̶o̶u̶g̶h̶ ̶y̶o̶u̶ ̶c̶a̶n̶ ̶a̶s̶s̶i̶g̶n̶ ̶a̶n̶ ̶i̶n̶t̶ ̶t̶o̶ ̶i̶t̶). If you don't want to allow that, you can just wrap it in a single member struct.

> 'type Foo int' in Go creates a new 'Foo' type that can't be used as an int without casting (although you can assign an int to it).

You can't, in fact:

    type Foo int

    func main() {
        var foo Foo = 1
        var bar int = 2

        foo = bar // cannot use bar (variable of type int) as Foo value in assignment
    }
The reason you can do things like:

    var foo Foo = 1
is that because numeric literals in Go are not ints, they are untyped [0].

[0] https://go.dev/blog/constants

Ah yes, good point. Thanks for the correction.
Yeah, his complaint about newtypes is just incorrect.
I moved some words around to make the nit less confused - thanks for the feedback!
Still not seeing it. You don't have to use interfaces to make an opaque type. A package boundary is sufficient.

Not sure why you would want a fully opaque type internally to a package anyway. A regular `type Foo Bar` declaration is sufficient to give you a `Foo` that can't be accidentally interchanged with a `Bar`.

That's not the only/main reason to want a newtype though - it's also about restricting what the value can be, see something like NonZeroU64: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU64.h...

numeric literals (mentioned by paskozdilar in a parent comment) being untyped is another footgun I hadn't even thought of including - it makes it impossible to achieve in TypeScript/Java-level enums.

You can define NonZeroU64 in Go exactly the same way it's defined in Rust – as a struct with a private field. No interfaces required.

But I was wondering why you would want an opaque type internally to a package. Presumably not to ensure that the value has passed some validation, since in that case you would want to encapsulate that validation logic in its own package. It's not like Go imposes a tax on packages. Packages are the unit of encapsulation in Go, just as modules are the unit of encapsulation in Rust.

> But I was wondering why you would want an opaque type internally to a package.

You can have a public function (a constructor) returning an instance of a private type. This way you ensure it's not zero-initialised by default (you can't do "var f privateType", you need to call the constructor).

But it's annoying to do. For every type you'd ever want to protect against zero-initialisation, you'd need to declare it private in some other package, and create a constructor. Therefore, most people just don't bother and prefer to live with the increased risk of bugs.

Zero initialization is a pretty fundamental concept in Go. I can see why people might not like it, but if you are trying to prevent a large number of types from being zero initialized then you are just going against the grain of the language. In most cases you can arrange to make the zero value valid.

To me it seems extremely weird to phrase this kind of criticism by saying that Go lacks proper support for newtypes, which simply isn’t true. If the author’s real complaint is with zero initialization then it would be a lot easier to understand their point if they made this explicit.

> But it's annoying to do. For every type you'd ever want to protect against zero-initialisation, you'd need to declare it private in some other package, and create a constructor.

How is this annoying? You’ll need a constructor anyway if you’re doing validation on the value. Apart from that you’re just complaining about having to make a package, but that’s really simple. I don’t see how Go would be improved by layering additional privacy mechanisms on top of the package system.

> Zero initialization is a pretty fundamental concept in Go.

I don't get it. There's nothing particularly special about it other than it being an explicit choice (I suspect Go's developers were lazy and did whatever was easier to implement). If, instead of automatically initializing to zero, the compiler said "error: uninitialized struct field", we wouldn't be having this conversation, and we wouldn't have this class of bugs. I would consider it "fundamental" if there was an obvious benefit from this choice, but I think a more appropriate word is "arbitrary".

> In most cases you can arrange to make the zero value valid.

Valid doesn't mean correct. Corrupting the DB with zero-initialized data can be worse than crashing early due to an unitialized (nil) pointer.

> If the author’s real complaint is with zero initialization then it would be a lot easier to understand their point if they made this explicit.

They did, it's mentioned in several places. E.g.:

---

Go fails to prevent many other classes of errors: it makes it easy to accidentally copy a mutex, rendering it completely ineffective, or leaving struct fields uninitialized (or rather, initialized to their zero value), resulting in countless logic errors.

---

> Apart from that you’re just complaining about having to make a package, but that’s really simple.

In order to prohibit direct struct initialization (which can be a source of unintended bugs) and enforce using the constructors, two types "related" to each other would have to live in different packages. E.g., if a type A's method constructs a type B, you'd segregate them and keep only the constructors public. In the context of a medium-sized project, you will end up with MANY packages. Sure, it's simple to create packages, but it can becomes painful to manage once you need to understand the code. So at the end of the day, people don't do it and instead elect to be "more careful", which isn't a good method of preventing bugs.

>There's nothing particularly special about it other than it being an explicit choice

Yes, this is what I meant. Go is explicitly designed according to the philosophy that it is beneficial overall for every type to have a default zero value. You may disagree with this, but if you find you are constantly fighting zero initialization, you should probably just use a different programming language.

>Valid doesn't mean correct.

I understand that. However, in most cases, you can arrange for zero to be a valid value. It may require a little creativity, but it's rare for it to be impossible in my experience.

As to packages, I still don't see the issue. The related types can be in subpackages of a parent package. And as you say, it's simple to create packages.

>So at the end of the day, people don't do it and instead elect to be "more careful", which isn't a good method of preventing bugs.

I don't think this choice has anything to do with the overhead of packages. Most people just don't like the style of 'bondage and discipline' coding where the type system is maximally exploited to enforce every possible invariant. Again, this is just fundamental to Go. It was designed by people who have explicitly said that they don't see value in using the type system this way.

By the way, I am no stranger to the possibilities in this space, having been paid to write Haskell code for a while. I've even done absurd things with the type system like this: https://adrummond.net/posts/cooper However, I tend to think the Go folks are right on this. It's good to have a basic type system, but there are rapidly diminishing returns on the fancier stuff.

You generally want newtypes as proofs that a value has gone through some validation.
And what prevents you using them this way in Go? Just make a package and export a constructor function that does the validation.
I think that was the author's point. You _can_ use them this way but it's a hassle and most people don't do it. The language itself doesn't protect you against zero-initialisation errors, even though it could.
(comment deleted)
One impediment is that Go cannot prevent the construction of invalid values, because every type has an implicit zero value:

  type NonZeroInt struct {
    v int
  }

  func (n NonZeroInt) Get() int {
    return n.v
  }

  var n NonZeroInt  // invalid!
You could of course validate on read:

  func (n NonZeroInt) Get() (int, bool) {
    if n.v == 0 {
      return 0, false
    }
    return n.v
  }
…but that's hardly good design.

You can improve on this marginally with an interface, because an interface's zero value is at least nil, which is, at least, explicit about whether there is a value or not. But it's not very elegant:

  type NonZeroInt interface {
    Get() int
  }

  type nonZeroInt struct {
    v int
  }

  func (n nonZeroInt) Get() { return n.v }

  func ToNonZeroInt(v int) (NonZeroInt, bool) {
    if v == 0 {
      return nil, false
    }
    return nonZeroInt{v}, true
  }
The biggest problem with this approach is that it adds overhead. It can also force values to be heap-allocated, though I believe Go will still optimize single-word interface values to avoid this.

Note that since Go interfaces use structural typing, naming the method Get() can cause issues:

  type AnyInt struct {
    v int
  }

  func (n AnyInt) Get() int {
    return n.v
  }
Now AnyInt fulfills the NonZeroInt interface, which is of course not something we want. So for types like these, it's a good idea to name the method explicitly:

  type NonZeroInt interface {
    GetNonZero() int
  }
Using interfaces here seems unnecessarily complex. If the default zero value were an issue in practice, I would just define

    type NonZeroInt *int

    OR

    type NonZeroInt struct { v *int } // (if you want it to be fully opaque)
so that the program would panic on an attempt to do arithmetic on the nil value. That achieves the same effect as your code, but without the unnecessary interface definition and the resulting naming issues. (Though note that Go does make it possible to export an interface from a package that no-one outside the package can implement. All you need to do is add a dummy private method to the interface.)

It's true of course that the pointer adds runtime overhead, but two points:

(1) Go is not really advertised as a zero cost abstraction language (in contrast to e.g. C++, Rust). So yes, building nice abstractions in Go will sometimes have a runtime cost. If that is unacceptable in a given application, then Go is not the right tool for the job. I'm not a Go zealot. If you need to do this kind of thing all over the place in your code base, then sure, don't use Go.

(2) If you are dealing with large arrays of non-zero ints (such that the overhead of boxing would be significant) then you could always define NonZeroIntArray.

Oh no, here we go again. So you don't like Go (no idea what this "golang" thing is everybody keeps talking about)? That's cool! You don't have to write yet another blog post saying that you really, really don't like it, with more strawman arguments and again quoting that quoted-to-death quote by Rob Pike about Go being designed for stupid developers, we got you the first time!
I'd just to point out that I think fanboys are not that useful and you have the right to don't read the article as much as he has the right to write it..
I dunno, aren't you just as guilty of not moving on? If Go is garbage, you defending it isn't going to suddenly correct that. Also, it's called golang because that's what a lot of people call it (i.e. https://www.reddit.com/r/golang/)
Then you could also say "He's called a [insert ethnic epithet here] because that's what a lot of people call him" - but I hope we can all agree that would be a bad idea?
I am not sure what you mean by your completely disconnected analogy.
> no idea what this "golang" thing is everybody keeps talking about

The Go FAQ can help you understand where this is coming from: https://go.dev/doc/faq#go_or_golang

I'm surprised this isn't mentioned, but "golang" is much easier as a keyword to search for then 'go' as well.
(comment deleted)
I don't have a horse in this race, but as for "Go" vs. "golang" - I imagine people use "golang" as it's a bit more clear that you're talking about a specific thing (the programming language), as opposed to a fairly common English word (and a board game, and probably some other uses).

From https://go.dev/doc/faq#go_or_golang:

Is the language called Go or Golang? The language is called Go. The "golang" moniker arose because the web site was originally golang.org. (There was no .dev domain then.) Many use the golang name, though, and it is handy as a label. For instance, the Twitter tag for the language is "#golang". The language's name is just plain Go, regardless.

Blog post is just one part, This person is whining about critical feedback received on HN at Twitter. Screenshotting users and comments for Twitter likes. For someone who doesn't like Go , they surely obsesses a lot about it.
Easier to search for things online with a unique moniker. I would use "golang" whenever I would talk about the language to IT people who may not know about it.
BTW The official github organization is literally "golang"

https://github.com/golang

Yeah, "golang" is the standin for when "go" is already taken (https://github.com/go). But still, the official name is "Go", and there's no good reason to not use it in the title of a blog post (other than SEO I guess)...
My site has its own search engine (just sqlite full-text search, nothing fancy) and searching for "go" is entirely unhelpful. So yes, external and internal SEO.
> rustlang

Rust is a chemical reaction, not a programming language. HTH. GLHF.

The author obviously doesn't like Go. Ok, he can have his own opinions.

I've been coding professionally since 1987, using everything from mainframe assembler, Fortran, C, VB, Java, C++, to most recently Go. IMHO, the language itself plays a smaller role in its usefulness than most think. As important is the tooling, stdlib, ecosystem, community and "StackOverflow"-ability.

Go has a few warts, like every language, but not that many, and they are more than made up for by how easy it is to assemble and run a project using it. It's that that makes it the most productive language I've used so far.

For me, the goroutines + channels + select is what makes Go leagues above any other popular language.

As far as I know, no other popular language allows you to read from multiple queues at the same time, which is an extremely useful pattern in concurrent programming. The only way to "select" from multiple sources in other languages is to use some kind of poll/select syscall on file descriptors - and even that is very limited, since kernel (at least Linux) does not allow userspace programs to create private file descriptors for intra-process communication - they must always be bound to some file/pipe/socket.

> As far as I know, no other popular language allows you to read from multiple queues at the same time

Off the top of my head, that's certainly possible in Rust, C++ and Java - probably many others I just don't know about.

That particular bit of concurrency goodness comes from the 70s, so you can be sure other languages picked it up.

As I understand it, he's talking about select/alt (i.e. guarded commands from CSP) being a native feature of the language rather than callback-based approaches. It's possible to implement CSP channels in most languages, but they're not first-class like go.
> It's possible to implement CSP channels in most languages, but they're not first-class like go.

But does that matter? In all my experience, I can't think of any instances where that wouldn't be a distinction without a difference. (Perhaps I'm missing something, though.)

Defaults matter because friction matters, but friction there is largely removed by having a decent package manager, so I personally don't think it matters (though the topic of "what batteries should be included" has far from run its course).
The minute you put language constructs in the base syntax and runtime of the language, it's a lot more than friction. Love it or hate it, Go is inextricably tied to CSP.
It matters a lot IMO. Most systems programming languages can implement whatever concurrency primitives you care to use, but most people default to whatever is provided by the OS/language because concurrency is hard. Having first-class syntactic sugar over a concurrent runtime bakes in a certain programming style in the language, which strongly determines how the language is used and the programming style. Go comes out of the Newsqueak/Aleph/Limbo family which has a very different style of programming compared to a lot of other languages.
I think there's a difference between 'in the standard library' and 'in the language', though. They seem to be praising Go for doing the latter. And the technical language in which it was expressed gave me to think there was some technical motivation for that, as opposed to sociological - but if what they meant is what you said, then I certainly wouldn't disagree with that.
I'd argue that Go is explicitly sociological. Most of the novel ideas in Go (process calculi/guarded commands in a concurrent language) were originally embedded in Cardelli and Pike's Squeak back in the 80s. The rest is trying to standardize the way scalable web applications are built.
It's the opposite - pointing out that X can just as well be implemented in language Y is the irrelevant point because anything can be implemented in any turing complete language.

Where languages differ is what they make easy to use, or first class.

As an example consider Go's autoformatter gofmt. It got released with the language, pushed and marketed as the way to format your code - first class. As a result, virtually all Go code is uniformly formatted. Contrast that with autoformatters in other languages pre-Go. They existed, but often multiple per language, each with hundreds of configuration options, all with minimal uptake in their ecosystems.

Ada too, I think.
Ada has had this built-in for decades, and even allows selecting from one of multiple waiting queues (entries) using a `select` keyword.
If you could spare some time, would you please demonstrate an example? Any language of those mentioned would be OK.
Here's a Rust example, with tokio: https://play.rust-lang.org/?version=stable&mode=debug&editio... - I don't have time to come up with Java/C++ examples, but I'm sure others will.

(If your point was about it being _built into the language_, then it definitely stands, see the other discussion in the parent comment thread)

Yeah, I guess I overestimated the complexity of such mechanisms. I mean, still, you need some kind of runtime for the asynchronicity, but the Rust version seems fairly OK (apart from the function coloring, but that's another story).

I guess I just like it being built into the language. Plus no function coloring (everything is asynchronous, but appears synchronous) really makes it easy to build complex systems.

>read from multiple queues at the same time

That's a trivial thing in javascript.

How? Javascript is single threaded run loop.
>read from multiple queues at the same time

Agreed, and things happening "at the same time" are possible only with parallelism. Hence my question =)

I interpreted "at the same time" as "without blocking",

But sure you could also add parallelism using a few built-in Node modules (there's cluster and worker threads, also don't know if atomics are already in Node, they are in V8),

It's not trivial anymore but also not that hard. A newcomer could figure it out in ~30 mins from the docs.

Gotcha, sounds like we interpreted it differently. I appreciate you taking the time to clarify, I am an old hand as JS but didn't know true parallelism had become feasible these days. Thank you, sincerely!
Don't worry, JS has come a long way.

During my PhD we had to crunch some numbers and my group usually makes use of C++ with libs for that. I tried doing it in Node using cluster and let it spread through our whole cluster of nodes (funny how it plays on words) and performance was worse obv. but not that bad, it was about 2x slower, but with that I was able to write code and test it in hours instead of days, and it didn't matter to me if a program that was going to take 2 hours was now taking 4 as I was going home anyway and check it out next morning ¯\_(ツ)_/¯. Plus, my experiment had a REST API for free (well, like 8 lines of code) and when I showed that to them they were :O.

If you could spare some time, would you please demonstrate an example?
Abusing notation a bit,

var a = new Queue();

var b = new Queue();

a.read(() => some callback);

b.read(() => some callback);

And code continues here without blocking.

To be honest, I think you could do the same in any (slightly) modern language.

Is the read() call running a task in the background? In that case, that's equivalent to launching two threads. For n queues, you'd need n tasks, and they'd hang in the background in case they never get a result and take up memory.
You can use Promise.race to wait for the first resolved promise.
here's some documentation on how to do it in C++ with boost in 2008, before go even existed: in this example two threads pull events from a single queue.

https://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tu...

(of course it was possible before)

I'm not really experienced with Boost so I'm having a hard time understanding what that snippet does. Is there any example that is completely self-contained (or at least limited to STL)?
Boost's io_service (since then renamed as io_context) is an implementation of a thread-safe event queue. Threads can put events in the queue (timer events, asynchronous read and write requests for networking, but one can also just push a generic lambda).

This example sets up two timers which will regularly push events in the queue, while two threads processes these events. It's from before c++ had lambdas - nowadays it can be written much more tersely.

I'll try to write a short example after when I'm not on my phone - it should be reduceable to 5-6 lines of setup at most

=> very dumb example of processing messages from ten threads

    #include <boost/asio.hpp>
    
    #include <atomic>
    #include <iostream>
    #include <thread>
    
    int main() {
      boost::asio::io_context io;
    
      using work_guard_type = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
      work_guard_type work_guard(io.get_executor());
    
      std::vector<std::jthread> t;
      for(int i = 0; i < 10; i++)
        t.emplace_back(std::jthread([&io] { io.run(); }));
      
      std::atomic_int counter{};
      while(counter < 100)
        io.post([&] { 
            std::cerr << std::this_thread::get_id() << '\n'; 
            counter++; 
        });
      
      io.stop();
      return 0;
    }
If that's all you want, Haskell has had goroutines (forkIO, yes it's called "fork" but it doesn't spawn an OS level process, that's forkOS), channels, and select since 1996. https://www.microsoft.com/en-us/research/wp-content/uploads/...
People also want a programming language they can easily read and that has enough market share to work well in team environments.
nobody should ever write haskell
Lots of languages have similar async, channel and pattern matching syntax these days. Kotlin, C#, off the top of my head. Probably a lot more.
A couple of things to add to this: the language spec is like a page long and very readable. Also the entire compiler toolchain and everything is written in Go and doesn’t depend llvm etc. This doesn’t help the developer but is a pretty unique aspect of Go.
> Also the entire compiler toolchain and everything is written in Go and doesn’t depend llvm etc.

Depends on which implementation you're talking about. One of the stated goals of the Go project is that there must not be just one implementation. gc does not, but tinygo depends on llvm. gccgo depends on gcc.

If a language spec is only a page long, it's leaving a bunch of important things unspecified.
Can you clarify further? Otherwise this seems like a shallow dismissal, which is against our HN community guidelines, and makes for uninteresting discussion.
Programming languages have a large amount of irreducible complexity. A page long spec for a language more complex than Brainfuck cannot represent the critical distinctions correctly.

Without that clarity, you end up with incompatible, spec-compliant implementations. This is a disaster, and so below a certain point relative to language complexity a shorter spec is simply wrong.

Are there nasty divergences between official go and cgo?
As it turns out, Go's spec is 105 pages long, not just one as was claimed upthread: https://go.dev/ref/spec

So the answer to your question is "not that I know of", but that's not evidence that a one-page spec is workable after all.

Thank you for showing us the light, jospehcsible!
Can you describe a coherent and consistent multithreaded model completely in 100 pages?
> Without that clarity, you end up with incompatible, spec-compliant implementations.

The Go team officially maintains two implementations, gc and gccgo, to ensure that implementation doesn't end up ruling over the specification as has happened in other languages. There are also other third party implementations, including tinygo.

Which spec-induced incompatibilities across these implementations are you referring to?

Go doesn't have a one-page spec, so what do you expect the GP to point to? You are proving his point.
Looks like one page to me: https://go.dev/ref/spec
Yeah, no.
Feel free to show us the second page.
It starts about 2/3 of the way through the table of contents.
A link is fine.
That points to the same page.
It's now become abundantly clear to everyone that you're using a different definition of "page" than everyone else in this conversation.
The only other person in this conversation is you, so not exactly the most representative of samples, but it is an interesting perspective. I've not heard anyone else consider the same HTML resource to be more than one page before. In fact, the term "single page application" hinges on a single HTML resource in the same way. The application may have more than one screen of content, but it is still considered one page.
oxnrtr is in this conversation too. And when describing the length of a document, "pages" universally means the number of printed pages it would occupy, not the number of computer files it's stored in.
There is no sign of anyone else participating in this conversation. Else we'd have heard their input by now. A page referring to a single HTML resource is standard nomenclature. Paper is antiquated technology, not how the Go specification is distributed, and carries no relevance to this discussion.
I hope you receive the help you need and deserve.
This has perhaps been my biggest pain-point with Golang..

Woe unto those who do not follow the idiosyncrasies of how golang handles versioning, package management, tooling etc.

if this is really your most important part of a language I would whole-heartedly recommend looking at rust which has been a breathe of fresh air in terms of package management and tooling.

Golang has the most hilarious approach to date formatting
(comment deleted)
Lol, I thought it was some sort of Joke when I first learnt it. And kept hunting for the 'proper' way. When I realised this was serious, I banged my head against the wall.
+100. I found a lot of the points in the post pretty silly/arbitrary, but if he had talked about date formatting I would be all aboard.
As an operations person who cares about deploying repeatable systems at scale, Rust's package management (and the toolchain's "packaging" itself) is an absolute nightmare. But at least I with MUSL can I have a 100% statically linked binary, which really should have been easier but that's another argument.

Seriously though, Rust team needs to have its Come To Jesus moment about not piping shit off the internet to sh.

I'm interested if you could elaborate on that?

My company deploys many Rust (web) applications to production and I've not experienced these issues with cargo

It's either a problem that you have or you don't, but also one that you have to have a specific mindset to even recognize.

To start off with, please read this: https://lwn.net/Articles/889924/

As you start having to worry about deploying to 10^5 scale machines you want your mindset to be more like the longtime kernel development folks. You want minimal dependencies. You want to build with minimal pulls to the internet. You want repeatable static binaries built from a source tree you can reasonably audit.

At that scale of deployment your "business risk" goes up significantly.

Rust's approach to tooling/packages looks very similar to the Node.js ecosystem. It's a total free for all and dependencies are managed really poorly (in the sense that they grow in number completely out of control).

You can use cargo vendor to import specific versions of your dependencies into your project for easy auditing, or cargo fetch to simply be more explicit about when to download from remote repositories (when combined with the --offline flag). The typical Rust "dependency" is small; it's more like a single .c or .cxx file than a conventional "library", except that it also plays nice with generic code unlike these languages.
I agree that Rust does suffer a similar problem to NPM where there are many small packages that people will use together.

I do wonder what the solution is though because Go has the same problem as far as I can tell. It has a bigger stdlib so there's less need to reach out. But when you do, you're in the same state with lots of tiny packages that do 1 thing well.

I don't have much experience outside of Go/Rust/Node so I can point to maybe a few languages which I can see being the opposite:

C++ has a large stdlib, and boost. With C++ managing dependencies is your problem so I guess it's easier to have few megapackages.

Python feels the same for mathematical computing. Numpy, TF, Pandas are all huge. Conda is an event bigger bundle, again I think because using the standard pip tools is rather cumbersome and usually not what people want to do

So as far as I can see, it's either easy to share code for others to use, in which case you get dependency hell, or you make it hard to share dependencies, but you have larger more refined ones as a result.

Hard to say what's better

rustup is available in your package manager's repository
No, it isn't. There is a package but it just symlinks to rustc & cargo. You still need to have run the installation manually.

And if you're still running something like CentOS 7, everyone just tells you to go download a Snap for it. eff that.

I love Rust as a language but its packaging mechanism is as flawed as all the others. I don't really see what breath of fresh air it brings.

I suppose you can define feature flags in your Cargo.toml but that's about it.

Go tooling is awesome compared to other language ( Rust included ). Everything is built it and you don't need something external, everything works out of the box dependencies included, it has been the case for 4 years with go mod.

The fact that you can cross compile a win10 .exe on a raspberry pi with a single command as easy as "GOARCH=amd64 GOOS=win go build ." it's very powerful and I don't know a single language that does it out of the box like go does.

Go tooling is one of the strongest point of Go you have all of that built-in:

- compilation

- testing

- benchamark

- dep managment

> it's very powerful and I don't know a single language that does it out of the box like go does.

zig build -Dtarget=x86_64-windows

I'm talking about mainstream language not stuff in dev. And go has been doing that for 10years+
well, not exactly. Zig is also crosscompiling C/C++ code, not just Zig. CGo doesn't do cross-compilation.
Yeah, it's pretty obvious to me the author doesn't like Go and some of the arguments raised really aren't concerns in (my very limited part of) the real world.

I've written a fair amount of Go and I am not bothered at all by the general ergonomics of the language. Some of the issues the author points out (like accidentally copying structs with embedded synchronization primitives) are caught by linters which you should be using regardless of what language you are coding in.

Edit: I dabble with Rust from time to time as well.

From the article: "[...] as developers get more and more senior, they tend to ignore more and more problems, because they've gotten so used to it. That's the way it's always been done, and they've learned to live with them, so they've stopped questioning it any more."
Hmm won't this apply to any language and therefore not a valid argument? A: language FOO is a great language! B: You are telling lies because you are fluent in this language and ignore the problems in the language.
Just speaking abstractly, whether problems are ignored has no bearing on the existence, size or count of the problems.
It seems to me there are two ways to evaluate the "beauty" of a language: there's the people who love the language theoretically (well constructed, coherent, nice typing, etc) and then there's people who love the usefulness/utility of the language.

For example, I hate python as a language (spaces syntax? Self,self,self, lack of static type, etc) but I've been using it lately and it's nice using it due to libraries, community,etc.

Yes. This is true of any environment. That's why I ask new hires to write down every WTF moment, every question and every idea for improvement they have as they get up to speed on our systems. Just because I'm used to avoiding a problem doesn't mean the problem must exist.
IME there are sort of two kinds of people here. People who are "fans" and defend "their" toy and people who don't. For example, I've been using Python for a very long time. I'm a "Senior Python Developer" so to speak. I quite like it for various purposes, but I can also talk your ear off about problems with Python.

I'd say if you run into someone who says they're experienced with X or love X etc., but they can't give criticism of it, they're most likely either not that experienced with X, or fanboys.

As developers get more and more senior, they have a different perspective on what constitutes a "serious" problem. Also, as developers get more experience with a language, they get better at doing things in ways that are idiomatic for that language - they work with the language instead of against it.

Take Haskell. If I were a Haskell novice, and tried to do everything procedurally with do notation, and then complained that Haskell had all these problems, would that make Haskell a bad language? No. Would it mean that all Haskell programmers were telling themselves lies in order to keep using it? No. It would mean that I was using it badly.

If I were a brand new programmer, and took up Java, I might well complain about "public static void main(String[] args)". But an experienced programmer would brush that off, telling me that that's just syntax - there are real problems with Java, but that isn't one.

So this particular statement, that senior and more experienced devs ignore more and more problems, isn't proof of anything. It's particularly not proof that developers have to keep lying to themselves in order to keep using Go. (They may, but this isn't proof.)

He made some good points in the article but this particular paragraph stuck out as being hypocritical. The entire motivation of him writing this was because he felt people dismissed his previous article out of hand. And then he makes a remark that preemptively dismisses any rebuttal out of hand (and as others have pointed out, can equally apply to any language so hardly a point worth complaining against Go specifically).
As developers get more and more senior they tend to ignore more and more problems because they realize the majority of them actually don't matter very much to doing useful work.
Or, perhaps more frequently, they can quickly see that any possible fix for it would be penny wise and pound foolish.
> as developers get more and more senior, they tend to ignore more and more problems, because they've gotten so used to it.

I've been coding professionally since the 90s. The last project I worked on was in Go. It was pleasant and surprisingly productive. A few warts, like the parent said, but all told it was a great experience. I'm now working on a Typescript project. It is painful. Typescript itself is quite nice, but the deep problems with the rest of the ecosystem have not gone unnoticed.

Im a go noobie so I had a question about the following.

> Go's lack of support for immutable data — the only way to prevent something from being mutated is to only hand out copies of it, and to be very careful to not mutate it in the code that actually has access to the inner bits.

I thought everything was handed out as copies in go by default unless a pointer was being passed. So this would make it “easy” to tell whether you are mutating a object or not.

would appreciate if anyone can clear that up for me.

side notes:

since Im still a junior, not too interested in language wars and feel like everything i touch i learn something from no matter how old/new it is.

honestly, i would never have the confidence to critic this <language> in that fashion. i cant convince myself that i know enough about language design/systems to critic anything that harshly.

maybe its my shortcoming as a junior :)

They mention it elsewhere in the post, but there are a few types that are essentially pointers but don't look like pointers. Slices, maps, interfaces, and channels (and also functions, but that isn't that important here). So you cannot just think that anything that doesn't have an asterisk is a copy.

Besides that, there is also the fact that slices share underlying array storage, and `append` doesn't make a copy unless there is still capacity, which means that you should be careful when working with subslices that get appended to.

https://go.dev/play/p/Iqd84_eAMNF

I see! Thank you for the example that was helpful.

I read through the example regarding the struct containing the map. I recently ran into that when working on something.

slightly meta: So how can one evaluate whether that is a good decision or bad?

Does forcing the programmer to use make explicitly for maps help prevent errors or is it tedious and better off having the zero value of map not cause errors?

I actually agree with the author that nils are a massive pain in the arse most of the time, and that Go would be much better off without them.

There is no precise, mathematical answer to your question, since it's always contingent on many things, but one way to evaluate a “correctness” of a design choice is the old adage that a good interface is hard to misuse. If your code can handle a nil map okay, and not requiring a non-nil map brings significant ergonomics advantages, you may not need to check it. Otherwise, I personally would err on the side of caution and design an API that either doesn't give the user a choice (i.e. creates the map itself) or returns an error if they provide invalid data.

(comment deleted)
The problem is that you can still mutate a copy. But does the person mutating the copy realize it's a copy, and that it won't propagate?

It's also hard to keep a mental model of which builtin primitives are values (copy semantics) and which are references (reference semantics).

Arrays are values. Slices are references, but might be a reference to some dynamically allocated slice or an array. Appending to a slice makes a copy _of the slice_, but which might modify the array it came from. It's not possible to tell from the type if it references an array or not.

Maps have reference semantics too. Why is it that maps and slices are the only references that don't have a pointer star to denote that?

Having followed language wars for a while as a relative newcomer to programming (longtime lab rat type), my present conclusion is that languages are just tools, comparable in my experience to different laboratory techniques and instrumentation. Different tools are appropriate for different purposes. Some are a lot less convenient than others to set up and use. Some are so obscure that nobody really supports them anymore, and if you want to use them you'll have little help with troubleshooting. Some are popular fads that come and go, as people realize there are better options available for particular jobs.

Once you learn how to use one set of tooling well, it's not so hard to jump over to another one if you get a job in a lab that relies heavily on it. Same with languages.

Fanatical adherents of one option or another often have some ulterior motive ... like the lab who spent $2 million on that high-field NMR spectroscopy machine and is always trying to get people to use it so they can can get some co-author publications. Often the most vitriolic fights are over some technical detail or other that doesn't apply to the vast majority of use cases.

Conclusion: meh. Of course Python and C++ are the superior options, however. Plus C for things like writing low-level code for firmware etc. The fact that these are the only languages I have any experience with is entirely incidental to the truth of this claim.

I definitely see that languages are just tools and you pick the right one for the job.

I guess the confusion for me is, languages often have overlapping usecases with slightly different semantics/syntax.

How do we objectively evaluate what is better? is it industry adoption? academic praise? im sure theres an answer to that but i havent went down that rabbit hole yet

“Languages are just tools.”

This is the most healthy take.

(comment deleted)
> I thought everything was handed out as copies in go by default unless a pointer was being passed. So this would make it “easy” to tell whether you are mutating a object or not.

The first bit is correct.

The point the article makes is that, to know whether a variable is potentially mutated, you have to go look at the signature of any function called on it. E.G. you can't just look at main and "know" whether a will get mutated or not, you have to also look at the signature of `Changed`. In C, with the following code

    #include <stdio.h>
    struct test {
 int value;
    }

    int main() {
        struct test a = test { value: 1 };
        Change(a);
        printf("a.Value = %d\n", a.Value);
    }
I can be 100% sure that a is never mutated, because it is passed to change value, and won't get automatically turned into a reference. Had Change be called with `&a`, then I'd know that a potentially gets mutated.

In Rust, `a` would have to be declared mutable to start with, e.g.

    fn main() {
        let mut a = A { value: 1 };
        a.Change();
        println!("{:?}", a);
    }
The above, I know that Change can potentially mutate a. And if a had been declared `let a`, I can be 100% sure that change cannot mutate it.

The direction go took is in line with many other languages (I think C++ behaves this way, it automatically turns values into references based on function signature).

i feel like that C example isnt fair cause you cant have functions bound to types right?? youre not calling change(a) but instead calling a.change(). i havent learned any rust yet, im waiting till im a little better at go so i can be comfortable at work before doing so:) whats the advantage of creating a function of type struct a rather than creating the C equivalent of change(obj structAtype) ? to me now, it seems that it should be expected that an a.Change func will mutate A i see what you’re saying that with Go it cant always be easy to check if its mutating what you’re calling or not. its giving the developer more options to use stuff by ref/val which gives more power but more room for mistakes.
> it seems that it should be expected that an a.Change func will mutate A

But you can make functions that have copied receivers:

    type Foo struct {
        bar int
    }

    func (f Foo) mutate() {
        f.bar = 2
    }

    func main() {
        f := Foo{bar: 1}
        f.mutate()
        fmt.Println(f.bar) // 1
    }
> whats the advantage of creating a function of type struct a rather than creating the C equivalent of change(obj structAtype)

types need to have methods in order to fulfill interfaces, that's all. (Well, and all the downstream benefits of using interfaces, such a polymorphism).

Okay, I haven’t worked with Go enough yet to need inheritance so I stupidly overlooked that :) even though ive used it extensively in java.

i can definitely see how that is wacky. i wonder what the upsides of being able to do that is.

really appreciate the explanation! thank you

(comment deleted)
I agree that this article is low-quality and self-contradictory, and flagged it too.

However,

> It reads as an asshole college sophomore who rips on plebs who dare to have different perspectives than them

This is going a bit too far, don't you think?

I don't know nothin' about Go. But this complaint really surprised me:

> Go not letting you do operator overloading, harking back to the Java days where a == b isn't the same as a.equals(b)

Does this guy really not understand that in a mutable language, (eq ...) is not the same as (equalp ...) and should never be confused with it?

Also: operator overloading is the spawn of Satan.

> operator overloading is the spawn of Satan

I used to agree with you, because of the abuse of operator overloading like iostreams and making DSLs with it. D does support it, but in a way that discourages non-arithmetic uses (such as it won't allow < <= >= > to be overloaded separately).

Operator overloading allows for things like complex numbers, arbitrary precision numeric types, etc., to be done with a library module.

> Operator overloading allows for things like complex numbers, arbitrary precision numeric types, etc., to be done with a library module.

Why is this desirable vs. implementing those types in the language itself?

I think we've gone down a weird path where implementing things "in userspace" is seen as an inherent good -- why?

> Why is this desirable vs. implementing those types in the language itself?

That's a very good question.

1. It's simpler. In D, we transitioned from a builtin complex type to a library type. It was a happy experience. The simpler the compiler, the easier it is to deal with.

2. Most any programmer can create a library type. Relatively few can modify a compiler to add a new type.

3. It takes the pressure off the compiler team to develop more arithmetic types.

4. Users can add arithmetic types without needing anybody's consent, and can do it right now.

5. It tests and verifies the metaprogramming abilities of the language.

Elaborating on 3/4: the domain experts don't need to be compiler experts too.

There are always going to be more numeric-like types (int, float, complex, bigint, rational, symbolic-comp types etc.). Numeric vectors that act like numbers are useful (see: numpy), and trying to stick those all into the language is far harder than allowing extensibility.

This is probably the best talk ever on the general topic: https://m.youtube.com/watch?v=_ahvzDzKdB0 [Growing a language by Guy Steele], seriously give it a look if you have the time and do put up with the seemingly strange start.

But at around the end it asks this (paraphrasing): Should a language have complex numbers implemented natively? Should it have numbers module n implemented natively? What about intervals, or rational numbers?

I also dislike the ridiculous overloading of cryptic symbols, but neither extreme is good. Not allowing overloading will give you BigDecimal.of(3).add(BigDecimal.ONE).divide… , while allowing it unrestricted will give you things like msg #!! something. But perhaps a sane middle ground is to allow only basic operators (+,-,*,/) to be overloadable.

The author definitely understands that. The point is: when you don't have operator overloading you get stuff like that which does demonstrably confuse many people

In languages with operator overloading this just isn't a concern at all because == does the obvious thing

== should do the obvious thing. But with operator overloading, it's not clear that it does, unless you need to read the implementation of == very carefully.
How is that any different to some opaque method call? By the same logic `a.equals(b)` might be doing something funky under the hood
True. But people think about it a bit differently. People don't always expect == to be a function call.
Sure, but I think '== might be a function call' is a lot less confusing than '== sometimes compares for equal value and sometimes doesn't'
> In languages with operator overloading this just isn't a concern at all because == does the obvious thing

And what is the obvious thing? It varies wildly among languages, even within C++ itself.

The obvious thing is to check if the contents are equal. I don't know what cursed C++ you're looking at if you're finding a ton of string implementations not doing exactly that...
Usually you do want to compare by value, so it should get the obvious syntax. When you want to compare by reference, you should write if(&a == &b) or ReferenceEquals(a, b) or something.
I don't get the problem with operator overloading. Yes, it can be implemented badly, but so can the equals() override. You can't even call a.equals(b) safely in many programming languages because either a or b could be null. I've run into so many null pointer exceptions in Java because someone wrote a.equals(b) when they clearly meant a!=null && a.equals(b).

Every time I have to write `BigDecimal sum = one.add(two).add(three).minus(four)` I cry a little. This is effectively no different from operator overloading and it's what special number implementations in all languages without operator overloading seem to end up doing out of necessity.

Without operator overloading, it is basically impossible to adapt a language for numerical computing/data science applications. Yeah, operator overloading is a powerful tool that's easy to abuse; no, it's not optional if you want the language to succeed at all in a whole bunch of applications.
Mathematica works just fine without user-defined operator overloading.
> Also: operator overloading is the spawn of Satan.

It's necessary for "powerful" generic programming. In fact, the entire reason user-defined data types can be easily used in C++ libraries like CGAL, Eigen, fmt, Kokkos, ranges-v3, etc, is because of operator overloading.

> Also: operator overloading is the spawn of Satan.

It is. And I'm glad Zig has none of that. `==` only works for primitives and you will never be confused.

Not sure that's a good idea. The concept of some types being special should not be something exposed to the user.
(comment deleted)
> Why does the Go compiler suddenly care if we provide explicit values now? If the language was self-consistent, it would let me omit both parameters, and just default to zero.

Without analyzing the rest of the post (which I read without having the skill to fully comprehend), this stuck out to me.

Perhaps the language behaves one way and not another by design? It's abstraction. By using a Struct, I'm telling the function "don't worry what is in this one box of data, just take it and process it as best you can" while defining two inputs to a function says "I demand that two pieces of data be present".

I don't think it's an inconsistency to see this behavior.

It is a very minor point and could easily be removed from the article, but I had that realization while writing those samples and it stuck with me.

I really think that if we follow the "zero values by default" philosophy, it wouldn't be shocking for Go to accept omitting function arguments and just zero them.

The fact that it doesn't, and insists on you passing the right number of arguments, makes the point that you can't in fact, just afford to zero out everything that isn't explicitly specified.

that's a trade-off with catching user errors, are you more likely to forget to pass an argument or need to pass a zero value?
why isn't it inconsistent to allow creation of a record with missing components but to deny creation of a stack frame with missing components
Unrelated (though a fun read) to the content: Thank you for making your blog readable. The typography choices are exemplary.
Meh, this blog post is a rather subjective rant. I can offer the opposite opinion, although I'm not sure that's helpful. The more I use Go, the more I like it. I'm very productive with it, similar to -- though not quite on a par yet -- the productivity I had when I was programming in REALBasic. Most of the benefits of Go result from the tooling and the availability of 3rd party, open source libraries with permissive licenses that are "good enough" for my purposes. I could probably also use Python instead and benefit from even more 3rd party support, but there would also be downsides to it. I appreciate Go's compact executables and easy deployment.

Quite honestly, in what concerns choices of languages, my experience is that it's not so much the language per se that counts, but rather the tooling, developer community, and the availability of 3rd-party libraries.

I believe he wrote a binary diff/patch system in it. If I had to do such a thing in Go, I would also hate Go.

He should just own up to trying to shove the square peg into the round hole and move on with his life, rather than blame the peg. There is no shame in it. At one point or another, we've all done it.

I generally like go and also see its problems as the author does.

However, with respect to the points about Go as a prototyping/starter language, there is not better language to start writing a project with in my opinion. Lots of languages have big communities of packages of various levels of maintenance but almost no other language has a standard library that is as usable as Go with the same guarantees between versions. I think its the biggest downfall of all these new languages like Rust/Zig/Hare etc, they all go for these minuscule standard libraries. I have no wish to start a project with any of them as all of them would involve I hunt down the 'best' http library and the 'best' async library and weigh their upsides and downsides, so I just reach for go and crack out the code I need to get it done, nothing else lets me do that half as easily, maintenance may be harder but at least I'm probably going to spend less time maintaining the list of packages that are still usable.

If you want a big standard library why not use something like Java or C#? I mean, you even have UI toolkits available from the get go
With Go you can develop a web service with few to no external deps or frameworks, compile it into a single, static binary and then deploy it in a minimal distroless container.

With Java and C# there's a lot of other fuss involved with figuring out deployment. The code, build, test cycle is also much slower in C#/.NET ime. That's starting to improve a bit with the newer dotnet, but still feels behind other everything but the kitchen sink frameworks like Rails, which I would more compare C# to since C# without .NET/dotnet is uncommon.

Java can literally hot-swap classes, how does it have a slower code-build-test cycle? It also has possibly the best debug mode and observability.
Sorry if it was unclear, I was specifically commenting about C# with regards to build, test, deploy cycle because I don't have much experience with Java. It's good to hear that it's not slow or cumbersome.
Thats a lot of nonsense. The developer loop is way faster now in C# with the introduction of hot reload.

> fuss involved

The commands are almost the same from the go tooling, dotnet build , dotnet run, dotnet format, dotnet test…

Anything outside of hellow world for a web sevice in go, you will use a third party library while in .NET its given to you.

I dont know them as well as I do Go but the libraries (java especially) don't feel as coherent as the go libraries do, though that may be subjective and to do with my lack of experience with them. In addition both of these languages are large enough and have projects structured in such a way as to make it difficult to just use a text editor, which i consider a barrier to me just 'cracking out' a project.

C# also had pretty middling linux support the last time i worked with dotnet. and java tooling is not as out of the box as go is where I have to know is gradle good or still used or should i just use maven. Its all part of me not wanting to have to choose the best dependencies for my project and being handed for the most part good enough dependencies by the language standard library.

Another thing to appreciate in go is it produces good enough binaries and produces them very very quickly -- i've worked on several massive go projects and the build/test turnaround time is quite good.

This is an opportunity piece written for no reason other than to ride the wave from a recent re-post of a 2 year old blog article. It offers nothing over the original blog post and it's difficult not to be cynical about the authors intent with this article.
>ride the wave from a recent re-post of a 2 year old blog article

You've been here a decade! This is part of the HN experience. I'm sure we'll have an Atlas Obscura submission about the scintillating history of Serbian skin-contact white wines later today.

I didn't care in the last post and I don't care about this one either. I care about my productivity, I care about my team's productivity, and I care about getting stuff shipped. Those are the things I care about, and go works great for that. If you care about those things too, and you're using go, you shouldn't stop using go.

My whole career people have been telling me to stop using languages or tools I've been productive with. I've built successful companies where everything was written in python, the whole time people on HN telling me how I was using a lowly language because of things like whitespace significance or strings that were not unicode by default.

If you care about other stuff, fine. If you don't think go works for you, don't use go. Just stop telling people who are using go (and other productive languages) to stop using them because of obscure language design issues or obscure API choices that people rarely encounter day to day. That isn't what matters to most people, and it's actually bad advice.

The problem is that there are a ton of less experienced people reading stuff on HN (just as I once was) who will take this to heart but have nothing actionable to gain from it, except to think they're a bad developer using a bad language. They aren't, and they're not.

I think your POV works in your very specific world view. As a head of an agency, hiring a developer that knows mainline languages serves a lot of good in hiring, keeping teams happy, and low turnover. We've all seen the agencies that hop on a new, hip language - only to go up in flames 6 months later because they couldn't find talent for their narrow viewpoint.

This isn't an argument against Go, moreso that your perspective is objectively elitist.

I don't think that the author is telling anyone to stop using Go. They are suggesting that there should be a better alternative, and there are lessons to be learnt.

I don't think we should be so cynical as to just lie down and accept that some things are just too hard to get right

Especially when other languages got them right.
I mean, this is Hacker News. Not corporate programmer news. Building a successful company has very little to do with tech choices. But that doesn't mean we shouldn't discuss these things as tinkerers and hackers.
> Building a successful company has very little to do with tech choices.

This is what Hacker News doesn't want to hear, and so needs to hear.

Like obsessing over the school supply list at the beginning of the year and getting everything perfect; it's not the whole of success, nor is it even really a huge part. But it can be fun.

So many companies succeed _despite_ their tech choices and so many fail also despite their tech choices.

In the end, even at mostly software companies, if you don't have a good sales model, a good sales team, a good marketing team, its likely you will out of business soon.

Two step profit plan:

1. Get a sales team that could sell shit on a stick.

2. Get a programming team that can do a bit better than shit on a stick.

I use Go. I'm not a Rustacean. I've also used a whole bunch of things that are not Go.

In reading this article, I'm finding myself agreeing with 100% of the author's criticisms. I've seen every specific problem mentioned be a thing that bogs companies I've worked for down and erode productivity. A lot of time the ops peoples' (aka: my) productivity specifically.

I haven't worked at a single company where teams of developers using Golang have been able to get the basic networking stuff right.

"Why are my TCP connections not closing? Why am I encountering port exhaustion?" Go's frustrating inability to inter-op matters quite a lot at the end of the day. GRPC and protobufs are f'in messy and full of footguns.

Thing is, I've been around the block. I know that these problems don't have to be problems. We have a tremendously bad tendency in this field to join cargo cults.

When looking for my next gig, if the company is big enough, I'm likely to start seeing Go as a negative, unless they've got that Tailscale kind of expertise.

"Why are my TCP connections not closing? Why am I encountering port exhaustion?"

This has nothing to do with Go. You're implying Go has a bug in its TCP implementation which I assume is false.

Networking works just fine in Go and it's actually easy to use.

https://pkg.go.dev/net

Edit: I'm getting downvoted but please share with TCP issues in Go.

> You're implying Go has a bug in its TCP implementation which I assume is false.

No, the parent is implying that Go's TCP implementation is easy to use incorrectly. Specifically in ways which cause the aforementioned issues.

I need examples, I used it for TCP/UDP and HTTP and beside the gotcha that clients have infinite timeout I don't see anything.
Read the article maybe?
The author of the blog post literally covered it in the article he wrote two years prior that's linked in the first sentence.

It's not "TCP issues in Go" it's "Go leaves you to figure these things out for yourself and write bad code that doesn't work if you don't thoroughly understand its gotchas."

Also, if you've been following Go over the years, you'll know that there's basically _always_ open issues (https://github.com/golang/go/issues/39063) in net & net/http about how Timeouts get mishandled and connections end up not being closed.

Cloudflare even had to write a whole (now old and outdated as hell) article explaining how to "do it properly" https://blog.cloudflare.com/the-complete-guide-to-golang-net... so that you don't footgun yourself.

Hmm not really, the only thing is the default http client that has no time out which is the case in many languages. The only issue I had was about idle connection and DNS resolution.

And the ticket you show does not show any issues on the Go side.

They really need to add a deprecation note to the default http server and client. I have seen SO many people trip over this.
> "Why are my TCP connections not closing? Why am I encountering port exhaustion?"

So… why?

> GRPC and protobufs are f'in messy and full of footguns.

Distributed data modeling is inherently messy and IME gRPC is one of the least messy, most scalable solutions to it. Or do you have a better alternative?

protobuf has issues with optional fields, as was pointed out in the post. Couple that with a language with a weak type system like golang (no sum types), and it's very verbose and slow to develop in. Targeting better languages helps alleviate the latter.
Ok, what's your alternative?
Because all protobuf fields are optional, they should be translated into optional fields in the target language (e.g. Optional<T>).
I believe that you are perfectly productive with Go, the article hasn't claimed otherwise.

I used to be quite productive with PHP. That does not mean PHP is a good language.

> The problem is that there are a ton of less experienced people reading stuff on HN (just as I once was) who will take this to heart but have nothing actionable to gain from it, except to think they're a bad developer using a bad language. They aren't, and they're not.

You are replying to an article mentioning many of Go's problems, without rebuking any of the article's points. Perhaps these poor people are using a bad language? (Also perhaps some people reading this are "bad developers", whatever that means? Perhaps I am! What does that matter?)

The article's author has written and shipped tons of quality Go code that is still used in production by many people, myself included.

Sometimes, a poor language is a good tool for specific task despite of being generally a poor language. Sometimes, knowing and liking a bad language makes you use it for tasks it's not suited for. Go is in the same category as JavaScript and PHP there, which have their valid uses, but also a lot of valid reasons to stay away from. You only learn how and when to choose them once you become experienced enough in several languages to notice the differences between them over long term usage and project maintenance.

As a beginner learning Go for the past 3 weeks, thanks for the last paragraph.

I was looking into a new language to learn outside of JS and Python. I wanted to learn a hot language. I did some digging between Rust and Go and found out that Go is more suitable for web backends, CLI apps, etc. while Rust was more of a contender to C/C++, as it was primarily was made to be used as a memory-safe, correct, strict language to write low level software.

I don't generally involve myself in the latter so I chose Go. I definitely want to learn Rust someday but is it worth it if I don't get into that low level of things?

What are Go's and Rust's target applications according to readers here?

Rust is a general purpose programming language. It can do low level systems programming but it's also highly capable of doing web backends, web frontends (wasm), game design, small utility scripts, etc.

A big thing people learning Rust do my mistake is to try and use all of the low level features straight away. Rust has tools like Rc, RefCell, Arc, and RwLock that let you have a garbage collected language (well, reference counted) and not worry about any of the low level memory management details.

See things like https://ggez.rs/ for games and https://www.arewewebyet.org/ for web stuff.

Although honestly I think if you're looking for a "hot" backend web language I'd say Elixir is the more well designed one than Go.

With your and the sibling commenters comment, I've made up my mind:

I'll definitely learn Rust one day and make stuff with it when I have proper time and I'm not learning anything else.

Thanks for the insights!

Rust is indeed a general purpose programming language, but unlike the sibling poster I'm not going to sell it for low-level systems programming _and_ other things just because it can and has some (hit-or-miss depending on the domain) crates for them.

Rust is a complex language and its APIs tend to reflect the underlying domain complexity nearly 1:1. It also does not have a GC. Rust interops with native code well. When you're writing code that needs to be very correct especially in complicated problem domains, Rust is a great language to reach for because it bubbles up that underlying complexity so well. If you really need the lack of GC pausing then Rust is also IMO much better than most other non-GC languages in common use (c.f. C, C++). If you need C interop, then Rust is great. If you're a fan of writing elegant abstractions, Rust is also a great tool as its macro processor and language constructs make it easy to write abstractions (compared to other imperative languages at least). But its use for other areas is, IMO, a bit fraught.

Go is a lot more opinionated as a language. Its stdlib hides the complexity for certain interfaces. It has a simple-to-use concurrency model that the whole language opts into. It compiles quickly. It produces a no-nonsense static binary and has a great cross-compilation story. Go code is repetitive but simple to read. Go's tooling is stellar and because of how easy it is to write third-party tooling, people often build useful tools for themselves. I find it really easy to hack on or debug other Go projects if needed. Overall, Go is opinionated, and if the applications you're writing and the style you're writing them in fall into Go's opinions then you'll love it. If you don't like Go's style, you'll hate it. Go is my go-to (pun not intended lol) language for hobby coding because when coding as a hobby I'm often working on a constrained problem and don't need Rust's complexity.

To offer a concrete example, the OP in his previous blog post wrote a diatribe about Go's filepath handling on Windows, but when I recently used Rust to write something that templated a few filenames, the whole thing took incredibly long. The complexities of Rust filepaths accurately reflect all the edge cases available for different platforms but was ridiculous overkill for my simple app that I was hacking on that was only ever going to run on a single Linux x64 platform.

IMO to just "get things done" use Go. If you find yourself fighting Go's idioms, then Go isn't for you. If you really enjoy writing elegant abstractions, Go isn't for you. If you need to go deep into an API that Go simplifies and will spend most of your logic doing just that, then Go isn't for you. If you can't tolerate the GC pauses then Go isn't for you. Otherwise just use Go to get stuff done.

Thank you for the detailed explanation! That actually clarifies a lot of things.

Indeed, there's no straight-forward answer to the question "Should I learn Rust as a web backend developer?". It depends on all of the above things you mentioned here.

Go: Trades off correctness with opinions and abstractions. Has a GC. Has a simple, dare I say old or not-modern, type system. Easy to pick up. Hard to have full control over the program.

Rust: Reflects and embraces the actual system with its complexity. Correctness is first and foremost as it deals with all the edge cases. Not easy to pick up. But worth it for critical projects.

In a realisation, why do people even compare these two? :)

> In a realisation, why do people even compare these two? :)

That's the puzzling thing. While the author doesn't explicitly call out Rust as the better alternative, if you look at his Twitter, it's fairly obvious his community is thinking of Rust. But I don't understand why. They're different languages with different strengths and weaknesses. If I'm writing a net service I'd rather write it in Go. If I'm writing something in OpenGL, I'd rather write it in Rust. There's no need to insult one another.

> I didn't care in the last post and I don't care about this one either. I care about my productivity, I care about my team's productivity, and I care about getting stuff shipped. Those are the things I care about, and go works great for that.

If your definition of "productivity" is the time spent in programming, I think you and the author are not in disagreement. The point that the author makes is that using a language with sophisticated type systems prevents some categories of bugs to happen in the first place. That means less time spent in debugging and fixing the code.

I use Go. I love Go. The reason why is pretty simple for me: It gets things done in a way that feels comfortable and has strong tooling. I am well aware it has shortcomings. I occasionally even run into them. However, as someone who doesn't particularly /like/ writing code, and instead sees it as the inevitable requirement of creating things that do something for me, I really appreciate that Go for the most part doesn't get in my way so I can make things that do something and move on.

I generally heavily preference scripting/interpreted languages over compiled languages, because compiled languages have a bevy of stuff that qualifies as "getting in my way". Go is refreshingly not like that, and therefore is the primary compiled language I use these days, and largely the primary language I use at all. Then again, I'm not an SWE. I'm a SysOps/SRE turned PM-T. So it's unlikely I would ever dig deeply enough to care about the particulars of a language's design other than knowing which problems it is best at and which problems a better choice can be made to solve.

Both this article and his previous article, I've read thoroughly. I understand and appreciate the criticism. But fundamentally there's seems to be an implicit assumption within both articles that other developers who use Go don't already know (most of) these things. Anyone who uses Go long enough will eventually run into some of its shortcomings. I'm not sure exactly why it rubs me the wrong way, but it feels like there's something subtlety insulting in the way the author presents his arguments. Like if we weren't all stupid rubes we'd just use whatever his preferred language is (Rust, presumably?).

The way people get zealoted about languages these days (especially some pretty terrible ones for getting things done) tempts me to just go back to writing Perl. In all the languages I've used over the years, I've probably got more raw work done in Perl than anything else, and it's still near and dear to my heart, despite being objectively a badly designed language.

I just don't see the issue with Go. After dealing with inscrutable errors in some python code that interfaces with OpenSSL. Or dealing with impossible to trace errors in Spring Boot. Or Javascript? An absolute nightmare from start to finish. There's something extremely nice to get an error, place a breakpoint and trace exactly (even if it's a third party library) that error is happening.

I will take all the footguns in the world for that ability. Plus in general the tooling is just amazing. I know there is other Unix tooling out there but I'm sorry, they kinda suck and are terrible to use. They're for the type of person who can use vim with their eyes closed and unfortunately that's not me.

The other footguns he mentioned? Valid. A linter will catch a chunk of them though. I just generally don't think they matter half the time. I think of it like the iPhone. It's a pleasure to use like 80% of the time maybe 85% and 10% it feels hacky and terrible to get something working and 5% you just can't or shouldn't do it.

So for the 80% use case (backend crud apps or backend web apis) I'd take Go every time. Plus it compiles almost instantly versus multi minute turnaround times in a lot of other languages.

> Or dealing with impossible to trace errors in Spring Boot.

Spring Boot is not Java. You can debug Java just as easily. On the upside, you can probably get the same stuff done in probably one third less code + use the vast ecosystem. On the downside, compilation may be a bit slower and you don't get a nice little executable out of the box.

I wrote a tool in Golang and while it did everything as advertised, the boilerplate just bogged me down. Any new changes is just so much more LOC compared to Java (or Python or Rust...). To be clear, I would prefer Java or Rust compared to Python any day. Either way, I just don't want to write so much verbose code anymore.

How is Spring Boot not Java? Spring Boot is a simple Java library.
Spring boot is not, in any way shape or form, a "simple" java "library". Not only is it a complex framework, it also uses features very few java programmers are exposed to, such as runtime code generation.
You can use runtime code generation with mere java.lang.reflect.Proxy. Yes, Spring is slightly more powerful than that, but it's not something magical. Runtime code generation is a simple concept.
I don’t think I’ve ever seen Java used in isolation without spring boot
This comment is hilarious ^
Y'all need to get out more often! ;)

Yes, Spring Boot is very popular, but there is a whole world of Java outside Spring, even if you confine yourself to just web apps (which is far from the only domain in which Java is used).

It’s worth remembering that Spring Boot didn’t exist for the first nineteen years we used Java.
Not a CS, but a damn good technical accountant and well self-taught developer.

I led a team that wrote an accounting & reporting software for a specific technical problem. We had an architect who only knew Spring, and hasn't been out there pretty much in a decade.

I clashed severely with him, to the point where he made an arrogant argument about something he was clearly wrong with. He said "I bet my salary that you're wrong" in front of people. I bet mine too, and the following day I demonstrated that he was wrong. I gave him my bank account (it was pay day). It was a hard bet to lose, so I said he didn't need to pay it, and I asked him to be removed from the team (because he showed that he wouldn't learn).

We went on to build the system without Spring, without TomCat and with more freedom to write SAL where an ORM couldn't solve the problem better.

Interestingly, we used grpc between the front-end and the backend JVM microservices.

As other people say, check out projects in GitHub. Look at what new Java, Kotlin, Scala projects look like.

There's a lot of interesting stuff in JVM-land that don't touch Spring.

Interestingly on the software that we wrote, compute was the biggest bottleneck. I rewrote some parts in Rust, but ended up canning the work because nobody else would be able or willing to touch the code.

I seriously doubt that Go would compile faster than Java. Like, neither does any reasonable amount of optimization, and I have never heard Java considered slow in compile time. Sure, one can do some very cryptic module-graph with their chosen build tool, but otherwise it should be as fast as it gets.
One more thing to note (on this post that is already on page 2 of HN after 47 minutes):

To me, as a scripter-ops kind of person, Go is useful as a Python variant. You get types, you get a huge standard library, and much of ops is network-based communication and glue code. The last job I had, I was tasked with rewriting a moderate Python lambda into golang as a POC for ease of use, and performance.

I relearned the basics of go in about two days, used google and docs copiously, but otherwise did not change the structure of the program.

The execution time was cut in half! It's an easy language to get using quickly and serves that purpose well. I wonder if the author could acknowledge the comparison to Python.

I use Go for simple CLI apps and it's pretty dang good for that. They're used by coworkers, contractors, and clients so the fact I can just send over an executable for any OS is really nice.

I wouldn't use it for anything too complex, or requiring a GUI. Mainly because I'd be much better off using the languages in my day job that I'm more familiar with.

It's the matter of one's opinion, I personally love it. The design has +n years of experience behind it and stands on shoulder of some serious people (yea you already know who they are).

Every language has its own gotchas, and if you are not satisfied with it, coding some Java might help you gain a little perspective.

Coding in Java is outright ok, compared to Go.

Also, you should read the article, it mentions reactions like yours.

This post should not have been flagged, just because people don't like hearing criticism of a language.
I'm not emotionally attached to Go, I want to learn rust, and I'm old enough to realize the search for the perfect tool is utter folly. So the inevitable religious wars that surround critiques like this don't move the needle for me.

So while this article didn't really convince me of anything, I have to admit I did learn a thing or two (or five). Kudos to the author, who is a fantastic writer and communicator. Even if you aren't neck deep in the language wars, it's worth reading.