Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It really is remarkable that Go has repeated all these mistakes, even with the benefit of having all of our field's history to learn from.

Loop variable scoping is not the only area where the designers of Go have failed to learn from past experience and instead opted for a design that lends itself to a more convenient implementation at the expense of exposing foot guns to the user: zero values are absolute dynamite, especially when combined with other language features like implicit zero initialisation of structs, multiple return values instead of sum types, or reflection-based magical JSON deserialization. When you have an empty string or a zero integer in Go, you can never be quite sure that the value you're holding is supposed to be what it is, rather than being an implicit zero value that snuck in at some point in place of a missing value.

Go also fails to offer any facilities to aid programmers in writing safe and correct concurrent code, beyond some fundamentally superficial language features like syntax extensions for channel types and spawning tasks. Channels are difficult to use correctly, usually having to be used in conjunction with some other synchronisation primitive like a WaitGroup, and compose poorly with implicit zero values resulting in the need to define semantics for fundamentally nonsense operations [1]. The language offers no facilities for restricting mutation, indeed in this respect, it's even worse than C. It's too easy to write buggy, racy code in Go.

There's no denying Go's initial allure, but in reality it fails to address in any systemic way the problems that have plagued the software development practice for decades. While other languages offer facilities for eliminating entire classes of bugs, all Go has to offer is an attitude that says "simply don't make mistakes." The whole language is a bitterly disappointing pile of missed opportunities. In the words of fasterthanlime, it's the billion dollar mistake all over again.

[1]: https://dave.cheney.net/2014/03/19/channel-axioms



> There's no denying Go's initial allure, but in reality it fails to address in any systemic way the problems that have plagued the software development practice for decade

I find comments like this illustrate perfectly the gap between these focused on language theoretics, and those focused on building software.

Go is successful because it strikes a strong balance between what practical software engineering organizations need from a language, of which safety is only one constraint.

Languages also need to be: * Easy "enough" to learn * Easy to read * Easy to write * Performant * Compile quickly * Have strong tooling * Have a strong standard library * Provide good solutions for it's problem domains * Support large code bases with many dependents ... * And be "safe*

Easy here is also influenced by what people already know, syntax and basic working methods need to be familiar to the vast majority of software engineers.

Go is successful because for many engineers it provides enough of all of the above with *enough" safety.

P.s. complex, difficult to understand languages incur more bugs then simple ones, even with additional safety.

PPS: If you think multiple returns and sumtypes solve the same thing, you've not thought very hard on the subject...


> P.s. complex, difficult to understand languages incur more bugs then simple ones, even with additional safety.

Do you have any info on this? My understanding of this has been that some types of complexity make code worse, and other types make code better. For example, ruby's metaprogramming has been a source of bugs because of it's complexity.

On the other hand, haskell is "complex and difficult" in terms of having a powerful type system. In my personal experience, I've found that haskell code has far fewer bugs than go code, and a large fraction of the bugs I encounter in go would not have been written in haskell or rust, in a language with a more powerful type system.

Do you have any info on this link between "complexity" and bugs?

> Go is successful [...]

That's unrelated to whether it has systematic problems. As is much of your post to be honest. Like, yeah, javascript is successful. Bash is successful. No one will argue that those languages don't have systematic problems.

The parent poster wasn't saying no one uses go, but that people use go despite its systematic problems, and tbh your comment mostly doesn't argue against that thesis, just arguing that it's successful. Which sure, yes, it is, that's not really related to the parent comment's claim that it's a poorly designed language.


> Do you have any info on this?

There have been some studies, and while all methodologies have tradeoff's go and clojure sit near the bottom of this list in bugs/committ: https://arxiv.org/pdf/1901.10220.pdf

Which is fascinating because they are very different languages whose unifying theme is simplicity.

But this actually fits well if you know another important fact: bugs occur along organizational lines. https://augustl.com/blog/2019/best_bug_predictor_is_organiza... If you've been around long enough, you realize a lot, if not most bugs, come from not understanding someone else's code. Type systems arn't going to help you, when you don't understand what the code they are "protecting" is doing.

> The parent poster wasn't saying no one uses go, but that people use go despite its systematic problems, and tbh your comment mostly doesn't argue against that thesis, just arguing that it's successful

But if go has so many problems why do people use it? Javascript, bash, and go have a unifying trait. They are useful, they solve a problem. But unlike javascript and bash, go wasn't and isn't integrated anywhere. No ecosystem forced people into go. They choose it, writ large. Why? Well because languages are more than there type systems.


> all methodologies have tradeoff's go and clojure sit near the bottom of this list in bugs/committ: https://arxiv.org/pdf/1901.10220.pdf

You have linked a study which, if you read the abstract, effectively claims "we tried to reproduce a study about bugs-by-programming-language, and could not. We have concluded their methodology was flawed".

I can't find information in your linked source that support anything about type-system complexity resulting in more bugs.

> But if go has so many problems why do people use it?

If candy is bad for your health, why do people eat it? Surely people eating candy is proof it's good for your health. That's the argument you're making here.

We can show candy is bad for your health, and the comment you originally replied to provided a mix of reasons why they saw go as having problems and ignoring programming research. All of those are more evidence than what you've replied with, which is essentially "but go is popular", entirely ignoring their concrete points.

Anyway, if people choosing a language is proof that a language doesn't have problems, that surely means PHP, Java, python, C, etc have fewer problems than Go since they all are used much more than it.

Again, a language being good and people using it are not necessarily related. People eat candy despite it being bad for them. People code in Go despite it being designed like "C, but with GC"

Perhaps rob pike said it best:

> The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt

As rob pike so clearly said, perhaps go is successful because it is intentionally a poorly designed language, intentionally one that eschews programming research in order to appeal to python programmers.


Rob Pike did not "clearly say" anything of the kind. You are badly distorting what he said. Maybe try reading it again without bias?

As for the rest of your post, you dismiss the study as flawed. Fine. But most of the rest is your candy analogy, which is also flawed. One could just as easily say that people like you like... whatever languages you like... in the same way that people like cocaine, because it makes them feel smarter than everyone else. Such "proof by analogy" doesn't say anything meaningful or arguable.

The one other thing you said is that "the language being good" and "being used" are two different things. But I have a different view of programmers than you seem to. They aren't toddlers with no self-control reaching for what's bad for them (or drug addicts either, in my flawed analogy). Programmers use languages because, despite their flaws, the languages are still better for their use case than the alternatives. You have to judge a language as a whole package - syntax, semantics, build-in libraries, third-party libraries, ability to find people who know it, help available on Stack Overflow, all of it. Go (and PHP and Java and C/C++) have significant market share because, for significant classes of problems, they still are better than the available alternatives.

I trust the people actually building stuff. They are the hardest people to fool.


> That's unrelated to whether it has systematic problems. As is much of your post to be honest. Like, yeah, javascript is successful. Bash is successful. No one will argue that those languages don't have systematic problems.

Right, bash and js have pretty significant problems, but they remain popular because they were developed as exclusive languages for platforms which became wildly popular; essentially they benefit from monopolies and network effects in a way that Go never has. The fact that Go is a popular language and still rapidly growing indicates that its issues are relatively minor compared with its advantages over other candidates (e.g., Haskell).

> On the other hand, haskell is "complex and difficult" in terms of having a powerful type system. In my personal experience, I've found that haskell code has far fewer bugs than go code, and a large fraction of the bugs I encounter in go would not have been written in haskell or rust, in a language with a more powerful type system.

Granted, but in my experience those languages trade off a lot of productivity in order to reduce bugs, and that leaves me a whole lot of time to debug Go programs and achieve a similar degree of correctness. Moreover, I often spend so much of my energy thinking about the type system in Rust/Haskell that I make silly mistakes that the type system doesn't catch (I've written a static site generator in Go and then in Rust, and I wrote a bunch of URL/filepath handling bugs in the Rust version that weren't present in the Go version--despite the benefit of hindsight--because I was focusing so much on the type system). Rust also makes it a lot more painful to create and use new integer types compared to Go (e.g., you have to define a ton of traits and even then you still have to wrap integer literals in MyIntegerType::new(0) and so on), so I see a lot of code that just passes around u64s as identifiers for different resource types and it's super easy to use the wrong u64 to index into the wrong resource collection.

I'm not saying that Rust results in more bugs on balance (I don't think it does) but that Go wins overall for most ordinary application code (but not for systems code, or high performance code, or real time / mission critical code).


> Languages also need to be:

> * Easy to read

The motivating examples of this whole proposal are examples where one reads the code and the semantics are unclear.

> PPS: If you think multiple returns and sumtypes solve the same thing, you've not thought very hard on the subject...

The stereotypical example of multiple returns in Go is functions that return val, err when they mean that they return one of a value or an error. Which is what sum types do.


> The stereotypical example of multiple returns in Go is functions that return val, err when they mean that they return one of a value or an error. Which is what sum types do.

The point is that with real sum types, the compiler will enforce that you return exactly one of a value or an error, whereas in Go, you're just supposed to do so, and it's possible to write code that mistakenly returns both or neither.


Yeah, but multiple returns are _used for other things_. So they encompass error returns _and other things_. Multiple returns by the way would be product types that are being automatically unpacked.

One of Go's core missions is to keep the number of concepts users need low. Multiple returns encompass the error use case and others.


Sure, and everything people do with sum types can also be done with plain C structs, and has been done like that in decades. But I think that saying that multiple returns (which are a sort of product type) “encompass” the error use case (logically a sum type) is overstating the case a bit. I would accept that returning errors can be achieved without sum types (and obviously is achieved without sum types in practice in the huge amount of code in languages that don’t have sum types).

But I would not personally design a new language without sum types or some other similarly strict solution for the kind of programming that will encounter errors.


I would suggest dialling the condescension down a bit mate.

There are many successful modern industrial languages out there that don't repeat the kinds of mistakes Go does. Kotlin is a strong example. So does the popularity of TypeScript show that we can successfully and fruitfully apply innovations from modern theory to industrial practise.

There's a tonne of real software being built in both of those languages. You don't need to ignore decades of research to build a successful and productive language.


You wrote the post you wrote. And then you accuse zbobet2012 of condescension? Physician, heal thyself.

Don't be so condescending to assume that Go's designers ignored decades of PL research. They knew it far better than you do.

And don't be condescending to the programmers, either. They aren't sheep who are led astray by shininess and PR. If that many programmers are using Go, then many of them find genuine value in Go. It solves enough actual problems well enough for it to get used, a lot.


> Go is successful because it strikes a strong balance between what practical software engineering organizations need from a language, of which safety is only one constraint.

This is a laughable claim when you've seen other languages (which have resulted in billion dollar companies with low engineering burden) that have done much better than go at this.

Go is successful for other reasons, mainly it plays into the biases of certain class of developers and managers.


> Go is successful for other reasons, mainly it plays into the biases of certain class of developers and managers.

While there is definitely an element of that, I think the main reason Go is successful are completely unrelated to the language itself. The main advantage of Go is that it is the one GC language with a slim runtime. Go programs are tiny compared to Java, C#, Python, Haskell etc. They start instantly. And they do so even if they are implementing an HTTP server or other non-trivial things.

So Go is excellent at something like containerized microservices, where you want to easily run dozens of containers on a single host, and rely on quick restarts for the occasional bug.


"The main advantage of Go is that it is the one GC language with a slim runtime"

I have worked in places (only startups, no big tech) that deployed go (okay, low n=2) and this was not a consideration.


> There's no denying Go's initial allure, but in reality it fails to address in any systemic way the problems that have plagued the software development practice for decades.

Eh, loop variable scoping has bitten me a single digit number of times in the eleven years I’ve been using it. Zero values are definitely more frustrating. Lack of Rust-like enums is another pain point.

But these are relatively minor compared to what Go gets right that other languages don’t—I would happily jump ship from Go the very moment something arrives that outperforms it for my use cases, and indeed I try out every language that I hear better-than-Go hype about.

So far Rust wins at systems programming, but even with the enums and lack of zero values I spend so much time fighting the language (not just the borrow checker) or implementing traits, etc—far more than I spend debugging nil pointers and such in Go. And frankly Rust is the only thing I’ve found that comes close. Go is just an extremely productive language even if it has a few sharp edges (after all, people still write really important code in C, C++, or even fully dynamic languages—compare that with zero values!).


> Eh, loop variable scoping has bitten me a single digit number of times in the eleven years I’ve been using it.

Go ahead and ask them to remove this from the Frequently Asked Question section then.

https://go.dev/doc/faq#closures_and_goroutines


Its presence in the FAQ indicates that a lot of people have run into it, not that people commonly repeat the mistake. What exactly do you think we're debating here?


This is a very one sided view. It reads like you have not familiarized yourself much with the internal reasoning behind these decisions. You can disagree with the balance that has been struck, but you don't appear to be aware of any balancing at all.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: