frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

Open in hackernews

Go is still not good

https://blog.habets.se/2025/07/Go-is-still-not-good.html
194•ustad•4h ago

Comments

keyle•3h ago
I use Go daily for work, alongside Dart, Python.

I say switching to Go is like a different kind of Zen. It takes time, to settle in and get in the flow of Go... Unlike the others, the LSP is fast, the developer, not so much. Once you've lost all will to live you become quite proficient at it. /s

written-beyond•2h ago
My developer experience was similar to rust but more frustrating because of the lax typing.

ISTG if I get downvoted for sharing my opinion I will give up on life.

aloukissas•1h ago
I also sing "Fade to Black" when I have to write go :D
theshrike79•1h ago
I've been writing small Go utilities for myself since the Go minor version number was <10

I can still check out the code to any of them, open it and it'll look the same as modern code. I can also compile all of them with the latest compiler (1.25?) and it'll just work.

No need to investigate 5 years of package manager changes and new frameworks.

figmert•2h ago
Has Go become the new PHP? Every now and then I see an article complaining about Go's shortcomings.
giancarlostoro•2h ago
No, this has been the case as long as Go has been around, then you look and its some C or C++ developer with specific needs, thats okay, its not for everyone.
ginko•2h ago
Go was announced as a replacement for C & C++ so I think it's reasonable to compare it to that.
Matl•1h ago
It was intended as a as a replacement for C & C++ for Google's use case of network services btw.
pjmlp•1h ago
Not really, no one at other other than the original authors though of that, the authors had an issue with C++ compile times and were sponsored by their manager to work on this Go side project of theirs.

Google's networking services keep being writen in Java/Kotlin, C++, and nowadays Rust.

wild_egg•1h ago
It hasn't been promoted that way for over a decade at this point.
jact•1h ago
I think with C or C++ devs, those who live in glass houses shouldn’t throw stones.

I would criticize Go from the point of view of more modern languages that have powerful type systems like the ML family, Erlang/Elixir or even the up and coming Gleam. These languages succeed in providing powerful primitives and models for creating good, encapsulating abstractions. ML languages can help one entirely avoid certain errors and understand exactly where a change to code affects other parts of the code — while languages like Erlang provided interesting patterns for handling runtime errors without extensive boilerplate like Go.

It’s a language that hobbles developers under the aegis of “simplicity.” Certainly, there are languages like Python which give too much freedom — and those that are too complex like Rust IMO, but Go is at best a step sideways from such languages. If people have fun or get mileage out of it, that’s fine, but we cannot pretend that it’s really this great tool.

gf000•1h ago
> I would criticize Go from the point of view of more modern languages that have powerful type systems like the ML

Go release date: 2012

ML: 1997

pjmlp•45m ago
You forgot: CLU 1977.

". They are likely the two most difficult parts of any design for parametric polymorphism. In retrospect, we were biased too much by experience with C++ without concepts and Java generics. We would have been well-served to spend more time with CLU and C++ concepts earlier."

https://go.googlesource.com/proposal/+/master/design/go2draf...

giancarlostoro•6m ago
My biggest nitpick against Go was, is and still is the package management. Rust did it so nice and NuGet (C#/.NET) got it so right that Microsoft added it as a built-in thing for Visual Studio, it was originally a plugin and not from Microsoft whatsoever, now they fully own it which is fine, and it just works.

Cargo is amazing, and you can do amazing things with it, I wish Go would invest in this area more.

Also funny you mention Python, a LOT of Go devs are former Python devs, especially in the early days.

pydry•2h ago
Go is a pretty good example of how mediocre technology that would never have taken off on its own merits benefits from the rose tinted spectacles that get applied when FAANG starts a project.
christophilus•1h ago
I don’t buy this at all. I picked up Go because it has fast compilation speed, produces static binaries, can build useful things without a ton of dependencies, is relatively easy to maintain, and has good tooling baked in. I think this is why it gained adoption vs Dart or whatever other corporate-backed languages I’m forgetting.
pydry•1h ago
I tried out one project because of these attributes and then scrapped it fairly quickly in favor of rust. Not enough type safety, too much verbosity. Too much fucking "if err != nil".

The language sits in an awkward space between rust and python where one of them would almost always be a better choice.

But, google rose colored specs...

christophilus•1h ago
I’m almost with you. If there was a language with a fast compiler, excellent tooling, a robust standard library, static binaries, and an F#-like type system, I’d never use anything else.

Rust simply doesn’t cut it for me. I’m hoping Roc might become this, but I’m not holding my breath.

gf000•30m ago
OCaml? Possibly Haskell as well?
theshrike79•1h ago
80% of what programmers write is API glue.

Go _excels_ at API glue. Get JSON as string, marshal it to a struct, apply business logic, send JSON to a different API.

Everything for that is built in to the standard library and by default performant up to levels where you really don't need to worry about it before your API glue SaaS is making actual money.

throwawayxcmz•1h ago
Exactly.

The other jarring example of this kind of deferring logical thinking to big corps was people defending Apple's soldering of memory and ssd, specially so on this site, until some Chinese lad proved that all the imagined issues for why Apple had to do such and such was bs post hoc rationalisation.

The same goes with Go, but if you spend enough time, every little while you see the disillusionment of some hardcore fans, even from the Go's core team, and they start asking questions but always start with things like "I know this is Go and holy reasons exists and I am doing a sin to question but why X or Y". It is comedy.

raincole•1h ago
It means many people are using it. That's it.
Xelbair•1h ago
Go was always 80% there,but the last missing(hard) 20% wasn't ever done.

It is infuriating because it is close to being good, but it will never get there - now due to backwards compatibility.

Also Rob Pike quote about Go's origins is spot on.

pjmlp•48m ago
On the contrary, PHP at least improves with times and embraces modern pratices in language design.
nikolayasdf123•2h ago
if this is the worst, not too bad.
giancarlostoro•2h ago
Agree, most of us arent needing niche C++ / C language features, what Go has for us is sufficient.
pif•2h ago
It doesn't need to be good because it is not meant for good developers.
Buttons840•1h ago
And it's perfect for most business software, because most businesses are not focused on building good software.

Go has a good-enough standard library, and Go can support a "pile-of-if-statements" architecture. This is all you need.

Most enterprise environments are not handled with enough care to move beyond "pile-of-if-statements". Sure, maybe when the code was new it had a decent architecture, but soon the original developers left and then the next wave came in and they had different ideas and dreamed of a "rewrite", which they sneakily started but never finished, then they left, and the 3rd wave of developers came in and by that point the code was a mess and so now they just throw if-statements onto the pile until the Jira tickets are closed, and the company chugs along with its shitty software, and if the company ever leaks the personal data of 100 million people, they aren't financially liable.

theshrike79•1h ago
Go has extremely robust linters just for the corporate use-case. And gofmt.

Every piece of code looks the same and can be automatically, neutrally, analysed for issues.

softwaredoug•2h ago
I like Go, but my main annoyance is deciding when to use a pointer or not use a pointer as variable/receiver/argument. And if its an interface variable, it has a pointer to the concrete instance in the interface 'struct'. Some things are canonically passed as pointers like contexts.

It just feels sloppy and I'm worried I'm going to make a mistake.

vbezhenar•2h ago
Just use pointers everywhere? Who cares.
softwaredoug•1h ago
But just not a pointer to an interface.

Its annoying to need to think about whether I’m working with an interface type of concrete type.

And if use pointers everywhere, why not make it the default?

grey-area•2h ago
I just always use pointers for structs.
nikolayasdf123•1h ago
I 80% of time use structs. common misunderstanding: it does not reduce performance for pointer vs value receivers (Go compiler generates same code for both, no copy of struct receiver happens). most of structs are small anyways, safe to copy. Go also automatically translates value receivers and pointer receivers back-and-forth. and if I see pointer I see something that can be mutated (or very large). in fact, if I see a pointer, I think "here we go.. will it be mutated?". written 400,000 LOC in Go, rarely seeing this issue.
spicyusername•1h ago
...do you want a copy or the original object?
tgv•47m ago
Yup, that's it. If you're going to modify a field in the receiver, or want to pass a field by reference, you're going to need a pointer. Otherwise, a value will do, unless ... that weird interface thing makes you. I guess that's the problem?
baq•2h ago
> Though Python is almost entirely refcounted, so one can pretty much rely on the __del__ finalizer being called.

yeah no. you need an acyclic structure to maybe guarantee this, in CPython. other Python implementations are more normal in that you shouldn't rely on finalizers at all.

sgarland•1h ago
I love Python, but the sheer number of caveats and warnings for __del__ makes me question if this person has ever read the docs [0]. My favorite WTF:

> It is possible (though not recommended!) for the __del__() method to postpone destruction of the instance by creating a new reference to it. This is called object resurrection.

[0]: https://docs.python.org/3/reference/datamodel.html#object.__...

guappa•1h ago
How does this relate to the claim of the parent comment that cyclic structures are never freed in python (which is false, btw)?
sgarland•1h ago
When I replied, the only thing the comment said was “yeah no.” I was agreeing that __del__ is fraught with peril.

Reading: cyclic GC, yes, the section I linked explicitly discusses that problem, and how it’s solved.

baq•1h ago
this is not what I claim, BTW.
thomashabets2•49m ago
Author here.

Yes, yes. Hence the words "almost" and "pretty much". For exactly this reason.

tex0•2h ago
If you don't like Go, then just let go. I hope nobody forces you to use it.

Some critique is definitely valid, but some of it just sounds like they didn't take the time to grasp the language. It's trade offs all the way. For example there is a lot I like about Rust, but still no my favorite language.

7thpower•1h ago
Which begs the question: What is your favorite language?
klabb3•1h ago
Disagree. Most critiques of Go I've read have been weak. This one was decent. And I say that as a big enjoyer of Go.

That said I really wish there was a revamp where they did things right in terms of nil, scoping rules etc. However, they've commited to never breaking existing programs (honorable, understandable) so the design space is extremely limited. I prefer dealing with local awkwardness and even excessive verbosity over systemic issues any day.

ben0x539•1h ago
Few things are truly forced upon me in life but walking away from everything that I don't like would be foolish. There is compromise everywhere and I don't think entering into a tradeoff means I'm not entitled to have opinions about the things I'm trading off.

I don't think the article sounds like someone didn't take the time to grasp the language. It sounds like it's talking about the kind of thing that really only grates on you after you've seriously used the language for a while.

ddlsmurf•1h ago
Sure but life choices are one thing, but this critique is still valuable. I learned a thing or two, and also think go can improve (I understand it's because I don't grok the language but I still prefer map to append in a loop)
blixt•2h ago
I've been using Go more or less in every full-time job I've had since pre-1.0. It's simple for people on the team to pick up the basics, it generally chugs along (I'm rarely worried about updating to latest version of Go), it has most useful things built in, it compiles fast. Concurrency is tricky but if you spend some time with it, it's nice to express data flow in Go. The type system is most of the time very convenient, if sometimes a bit verbose. Just all-around a trusty tool in the belt.

But I can't help but agree with a lot of points in this article. Go was designed by some old-school folks that maybe stuck a bit too hard to their principles, losing sight of the practical conveniences. That said, it's a _feeling_ I have, and maybe Go would be much worse if it had solved all these quirks. To be fair, I see more leniency in fixing quirks in the last few years, like at some point I didn't think we'd ever see generics, or custom iterators, etc.

The points about RAM and portability seem mostly like personal grievances though. If it was better, that would be nice, of course. But the GC in Go is very unlikely to cause issues in most programs even at very large scale, and it's not that hard to debug. And Go runs on most platforms anyone could ever wish to ship their software on.

But yeah the whole error / nil situation still bothers me. I find myself wishing for Result[Ok, Err] and Optional[T] quite often.

guappa•1h ago
> The type system is most of the time very convenient

In what universe?

theshrike79•1h ago
In mine. It's Just Fine.

Is it the best or most robust or can you do fancy shit with it? No

But it works well enough to release reliable software along with the massive linter framework that's built on top of Go.

xyzzyz•1h ago
Go was designed by some old-school folks that maybe stuck a bit too hard to their principles, losing sight of the practical conveniences.

I'd say that it's entirely the other way around: they stuck to the practical convenience of solving the problem that they had in front of them, quickly, instead of analyzing the problem from the first principles, and solving the problem correctly (or using a solution that was Not Invented Here).

Go's filesystem API is the perfect example. You need to open files? Great, we'll create

  func Open(name string) (*File, error)
function, you can open files now, done. What if the file name is not valid UTF-8, though? Who cares, hasn't happen to me in the first 5 years I used Go.
nasretdinov•1h ago
Note that Go strings can be invalid UTF-8, they dropped panicking on encountering an invalid UTF string before 1.0 I think
xyzzyz•1h ago
This also epitomizes the issue. What's the point of having `string` type at all, if it doesn't allow you to make any extra assumptions about the contents beyond `[]byte`? The answer is that they planned to make conversion to `string` error out when it's invalid UTF-8, and then assume that `string`s are valid UTF-8, but then it caused problems elsewhere, so they dropped it for immediate practical convenience.
assbuttbuttass•1h ago
string is just an immutable []byte. It's actually one of my favorite things about Go that strings can contain invalid utf-8, so you don't end up with the Rust mess of String vs OSString vs PathBuf vs Vec<u8>. It's all just string
zozbot234•30m ago
Rust &str and String are specifically intended for UTF-8 valid text. If you're working with arbitrary byte sequences, that's what &[u8] and Vec<u8> are for in Rust. It's not a "mess", it's just different from what Golang does.
gf000•16m ago
If anything that will make Rust programs likely to be correct under any strange text input, while Go might just handle the happy path of ASCII inputs.

Stuff like this matters a great deal on the standard library level.

roncesvalles•1h ago
I've always thought the point of the string type was for indexing. One index of a string is always one character, but characters are sometimes composed of multiple bytes.
birn559•40m ago
You can't do that in a performant way and going that route can lead to problems, because characters (= graphemes in the language of Unicode) generally don't always behave as developers assume.
crazygringo•27m ago
Yup. But to be clear, in Unicode a string will index code points, not characters. E.g. a single emoji can be made of multiple code points, as well as certain characters in certain languages. The Unicode name for a character like this is a "grapheme", and grapheme splitting is so complicated it generally belongs in a dedicated Unicode library, not a general-purpose string object.
0x000xca0xfe•57m ago
Why not use utf8.ValidString in the places it is needed? Why burden one of the most basic data types with highly specific format checks?

It's far better to get some � when working with messy data instead of applications refusing to work and erroring out left and right.

naikrovek•55m ago
I think maybe you've forgotten about the rune type. Rune does make assumptions.

[]Rune is for sequences of UTF characters. rune is an alias for int32. string, I think, is an alias for []byte.

tialaramex•5m ago
Rust apparently got relatively close to not having &str as a primitive type and instead only providing a library alias to &[u8] when Rust 1.0 shipped.

Score another for Rust's Safety Culture. It would be convenient to just have &str as an alias for &[u8] but if that mistake had been allowed all the safety checking that Rust now does centrally has to be owned by every single user forever. Instead of a few dozen checks overseen by experts there'd be myriad sprinkled across every project and always ready to bite you.

koakuma-chan•1h ago
> What if the file name is not valid UTF-8

Nothing? Neither Go nor the OS require file names to be UTF-8, I believe

johncolanduoni•1h ago
Well, Windows is an odd beast when 8-bit file names are used. If done naively, you can’t express all valid filenames with even broken UTF-8 and non-valid-Unicode filenames cannot be encoded to UTF-8 without loss or some weird convention.

You can do something like WTF-8 (not a misspelling, alas) to make it bidirectional. Rust does this under the hood but doesn’t expose the internal representation.

ants_everywhere•1h ago
> they stuck to the practical convenience of solving the problem that they had in front of them, quickly, instead of analyzing the problem from the first principles, and solving the problem correctly (or using a solution that was Not Invented Here).

I've said this before, but much of Go's design looks like it's imitating the C++ style at Google. The comments where I see people saying they like something about Go it's often an idiom that showed up first in the C++ macros or tooling.

I used to check this before I left Google, and I'm sure it's becoming less true over time. But to me it looks like the idea of Go was basically "what if we created a Python-like compiled language that was easier to onboard than C++ but which still had our C++ ergonomics?"

jerf•26m ago
While the general question about string encoding is fine, unfortunately in a general-purpose and cross-platform language, a file interface that enforces Unicode correctness is actively broken, in that there are files out in the world it will be unable to interact with. If your language is enforcing that, and it doesn't have a fallback to a bag of bytes, it is broken, you just haven't encountered it. Go is correct on this specific API. I'm not celebrating that fact here, nor do I expect the Go designers are either, but it's still correct.
herbstein•9m ago
Much more egregious is the fact that the API allows returning both an error and a valid file handle. That may be documented to not happen. But look at the Read method instead. It will return both errors and a length you need to handle at the same time.
traceroute66•1h ago
> Just all-around a trusty tool in the belt

I agree.

The Go std-lib is fantastic.

Also no dependency-hell with Go, unlike with Python. Just ship an oven-ready binary.

And what's the alternative ?

Java ? Licensing sagas requiring the use of divergent forks. Plus Go is easier to work with, perhaps especially for server-side deployments.

Zig ? Rust ? Complex learning curve. And having to choose e.g. Rust crates re-introduces dependency hell and the potential for supply-chain attacks.

theshrike79•1h ago
uv + the new way of adding the required packages in the comments is pretty good.

you can go `uv run script.py` and it'll automatically fetch the libraries and run the script in a virtual environment.

Still no match for Go though, shipping a single cross-compiled binary is a joy. And with a bit of trickery you can even bundle in your whole static website in it :) Works great when you're building business logic with a simple UI on top.

richid•1h ago
I've been out of the Python game for a while but I'm not surprised there is yet another tool on the market to handle this.

You really come to appreciate when these batteries are included with the language itself. That Go binary will _always_ run but that Python project won't build in a few years.

traceroute66•1h ago
> you can go `uv run script.py` and it'll automatically fetch the libraries and run the script in a virtual environment.

Yeah, but you still have to install `uv` as a pre-requisite.

And you still end up with a virtual environment full of dependency hell.

And then of course we all remember that whole messy era when Python 2 transitioned to Python 3, and then deferred it, and deferred it again....

You make a fair point, of course it is technically possible to make it (slightly) "cleaner". But I'll still take the Go binary thanks. ;-)

porridgeraisin•1h ago
> std-lib

Yes, My favourite is the `time` package. It's just so elegant how it's just a number under there, the nominal type system truly shines. And using it is a treat. What do you mean I can do `+= 8*time.Hour` :D

candiddevmike•1h ago
The way Go parses time strings by default is insane though, even the maintainers regret it. It's a textbook example of being too clever.
tux3•1h ago
Unfortunately it doesn't have error handling, so when you do += 8 hours and it fails, it won't return a Go error, it won't throw a Go exception, it just silently does the wrong thing (clamp the duration) and hope you don't notice...

It's simplistic and that's nice for small tools or scripts, but at scale it becomes really brittle since none of the edge cases are handled

pansa2•44m ago
As long as you don’t need to do `hours := 8` and `+= hours * time.Hour`. Incredibly the only way to get that multiplication to work is to cast `hours` to a `time.Duration`.

In Go, `int * Duration = error`, but `Duration * Duration = Duration`!

gf000•1h ago
> Java ? Licensing sagas requiring the use of divergent forks. Plus Go is easier to work with, perhaps especially for server-side deployments

Yeah, these are sagas only, because there is basically one, single, completely free implementation anyone uses on the server-side and it's OpenJDK, which was made 100% open-source and the reference implementation by Oracle. Basically all of Corretto, AdoptOpenJDK, etc are just builds of the exact same repository.

People bringing this whole license topic up can't be taken seriously, it's like saying that Linux is proprietary because you can pay for support at Red Hat..

pjmlp•1h ago
There are other JVMs that do not descend from OpenJDK, but in general your point stands.
gf000•1h ago
Yeah I know, but people have trouble understanding the absolutely trivial licensing around OpenJDK, let's not bring up alternative implementations (which actually makes the whole platform an even better target from a longevity perspective! There isn't many languages that have a standard with multiple, completely independent impls).
traceroute66•1h ago
> People bringing this whole license topic up can't be taken seriously

So you mean all those universities and other places that have been forced to spend $$$ on licenses under the new regime also can't be taken seriously ? Are you saying none of them took advice and had nobody on staff to tell them OpenJDK exists ?

Regarding your Linux comment, some of us are old enough to remember the SCO saga.

Sadly Oracle have deeper pockets to pay more lawyers than SCO ever did ....

gf000•1h ago
I have made a bunch of claims, that are objectively true. From there, basic logical inference says that you can completely freely use Java. Anything else is irrelevant.

I don't know what/which university you talk about, but I'm sure they were also "forced to pay $$$" for their water bills and whatnot. If they decided to go with paid support, then.. you have to pay for it. In exchange you can a) point your finger at a third-party if something goes wrong (which governments love doing/often legally necessary) b) get actual live support on Christmas Eve if needed.

traceroute66•31m ago
TL;DR: Its impossible to know if anyone on campus has downloaded Oracle Java....

Quote from this article:[1]

     *He told The Register that Oracle is "putting specific Java sales teams in country, and then identifying those companies that appear to be downloading and... then going in and requesting to [do] audits. That recipe appears to be playing out truly globally at this point."*

[1] https://www.theregister.com/2025/06/13/jisc_java_oracle/
gf000•19m ago
That's also true of torrented PhotoShop, Microsoft Office, etc..

Also, as another topic, Oracle is doing audits specifically because their software doesn't phone home to check licenses and stuff like that - which is a crucial requirement for their intended target demographics, big government organizations, safety critical systems, etc. A whole country's healthcare system, or a nuclear power base can't just stop because someone forgot to pay the bill.

So instead Oracle just visits companies that have a license with them, and checks what is being used to determine if it's in accord with the existing contract. And yeah, from this respect I also heard of a couple of stories where a company was not using the software as the letter of the contract, e.g. accidentally enabling this or that, and at the audit the Oracle salesman said that they will ignore the mistake if they subscribe to this larger package, which most manager will gladly accept as they can avoid the blame, which is questionable business practice, but still doesn't have anything to do with OpenJDK..

piva00•58m ago
> So you mean all those universities and other places that have been forced to spend $$$ on licenses under the new regime also can't be taken seriously ? Are you saying none of them took advice and had nobody on staff to tell them OpenJDK exists ?

This info is actually quite surprising to me, never heard of it since everywhere I know switched to OpenJDK-based alternatives from the get-go. There was no reason to keep on the Oracle one after the licencing shenanigans they tried to play.

Why do these places kept the Oracle JDK and ended up paying for it? OpenJDK was a drop-in replacement, nothing of value is lost by switching...

traceroute66•30m ago
TL;DR: Its impossible to know if anyone on campus has downloaded Oracle Java....Oracle monitors downloads and sends in the auditors...

See link/quote in my earlier reply above.

tempay•1h ago
> Rust crates re-introduces dependency hell and the potential for supply-chain attacks.

I’m only a casual user of both but how are rust crates meaningfully different from go’s dependency management?

tzekid•51m ago
I think it's because go's community sticks close to the standard library:

e.g. iirc. Rust has multiple ways of handling Strings while Go has (to a big extent) only one (thanks to the GC)

jaas•44m ago
Go has a big, high quality standard library with most of what one might need. Means you have to bring in and manage (and trust) far fewer third party dependencies, and you can work faster because you’re not spending a bunch of time figuring out what the crate of the week is for basic functionality.
zozbot234•24m ago
Rust intentionally chooses to have a small standard library to avoid the "dead batteries" problem. But the Rust community also maintains lists of "blessed" crates to try and cope with the issue of having to trust third-party software components of unknown quality.
theshrike79•1h ago
People tend to refer to the bit where Discord rewrote a bit of their stack in Rust because Go GC pauses were causing issues.

The code was on the hot path of their central routing server handling Billions (with a B) messages in a second or something crazy like that.

You're not building Discord, the GC will most likely never be even a blip in your metrics. The GC is just fine.

kace91•1h ago
My feeling is that in terms of developer ergonomics, it nailed the “very opinionated, very standard, one way of doing things” part. It is a joy to work on a large microservices architecture and not have a different style on each repo, or avoiding formatting discussions because it is included.

The issue is that it was a bit outdated in the choice of _which_ things to choose as the one Go way. People expect a map/filter method rather than a loop with off by one risks, a type system with the smartness of typescript (if less featured and more heavily enforced), error handling is annoying, and so on.

I get that it’s tough to implement some of those features without opening the way to a lot of “creativity” in the bad sense. But I feel like go is sometimes a hard sell for this reason, for young devs whose mother language is JavaScript and not C.

j1elo•1h ago
> People expect a map/filter method

Do they? After too many functional battles I started practicing what I'm jokingly calling "Debugging-Driven Development" and just like TDD keeps the design decisions in mind to allow for testability from the get-go, this makes me write code that will be trivially easy to debug (specially printf-guided debugging and step-by-step execution debugging)

Like, adding a printf in the middle of a for loop, without even needing to understand the logic of the loop. Just make a new line and write a printf. I grew tired of all those tight chains of code that iterate beautifully but later when in a hurry at 3am on a Sunday are hell to decompose and debug.

williamdclt•55m ago
I'll agree that explicit loops are easier to debug, but that comes at the cost of being harder to write _and_ read (need to keep state in my head) _and_ being more bug-prone (because mutability).

I think it's a bad trade-off, most languages out there are moving away from it

kace91•42m ago
I'm not a hard defender of functional programming in general, mind you.

It's just that a ridiculous amount of steps in real world problems can be summarised as 'reshape this data', 'give me a subset of this set', or 'aggregate this data by this field'.

Loops are, IMO, very bad at expressing those common concepts briefly and clearly. They take a lot of screen space, usually accesory variables, and it isn't immediately clear from just seing a for block what you're about to do - "I'm about to iterate" isn't useful information to me as a reader, are you transforming data, selecting it, aggregating it?.

The consequence is that you usually end up with tons of lines like

userIds = getIdsfromUsers(users);

where the function is just burying a loop. Compare to:

userIds = users.pluck('id')

and you save the buried utility function somewhere else.

apwell23•1h ago
> But yeah the whole error / nil situation still bothers me. I find myself wishing for Result[Ok, Err] and Optional[T] quite often.

I got insta rejected in interview when i said this in response to interview panels question about 'thoughts about golang' .

Like they said, 'interview is over' and showed me the (virtual) door. I was stunned lol. This was during peak golang mania . Not sure what happened to rancherlabs .

tgv•1h ago
I find Result[] and Optional[] somewhat overrated, but nil does bother me. However, nil isn't going to go away (what else is going to be the default value for pointers and interfaces, and not break existing code?). I think something like a non-nilable type annotation/declaration would be all Go needs.
blixt•34m ago
Yeah maybe they're overrated, but they seem like the agreed-upon set of types to avoid null and to standardize error handling (with some support for nice sugars like Rust's ? operator).

I quite often see devs introducing them in other languages like TypeScript, but it just doesn't work as well when it's introduced in userland (usually you just end up with a small island of the codebase following this standard).

xtracto•53m ago
I recently started writing Go for a new job, after 20 years of not touching a compiled language for something serious (I've done DevKitArm dev. as a hobby).

I know it's mostly a matter of tastes, but darn, it feels horrible. And there are no default parameter values, and the error hanling smells bad, and no real stack trace in production. And the "object orientation" syntax, adding some ugly reference to each function. And the pointers...

It took me back to my C/C++ days. Like programming with 25 year old technology from back when I was in university in 1999.

pjmlp•51m ago
And then people are amazed for it to achieve compile times, compiled languages were already doing on PCs running at 10 MHz within the constraints of 640 KB (TB, TP, Modula-2, Clipper, QB).
remus•45m ago
> [some] compiled languages were already doing on PCs running at 10 MHz within the constraints of 640 KB

Many compiled languages are very slow to compile however, especially for large projects, C++ and rust being the usual examples.

gf000•35m ago
Well, spewing out barely-optimized machine code and having an ultra-weak type system certainly helps with speed - a la Go!
zozbot234•8m ago
Golang is great for problem classes where you really, really can't do away with tracing GC. That's a rare case perhaps, but it exists nonetheless. Most GC languages don't have the kind of high-performance concurrent GC that you get out of the box with Golang, and the minimum RAM requirements are quite low as well. (You can of course provide more RAM to try and increase overall throughput, and you probably should - but you don't have to. That makes it a great fit for running on small cloud VM's, where RAM itself can be at a premium.)
torginus•1h ago
I still don't understand why defer works on function scope, and not lexical scope, and nobody has been able to explain to me the reason for it.

In fact this was so surprising to me is that I only found out about it when I wrote code that processed files in a loop, and it started crashing once the list of files got too big, because defer didnt close the handles until the function returned.

When I asked some other Go programmers, they told me to wrap the loop body in an anonymus func and invoke that.

Other than that (and some other niggles), I find Go a pleasant, compact language, with an efficient syntax, that kind of doesn't really encourage people trying to be cute. I started my Go journey rewriting a fairly substantial C# project, and was surprised to learn that despite it having like 10% of the features of C#, the code ended up being smaller. It also encourages performant defaults, like not forcing GC allocation at every turn, very good and built-in support for codegen for stuff like serialization, and no insistence to 'eat the world' like C# does with stuff like ORMs that showcase you can write C# instead of SQL for RDBMS and doing GRPC by annotating C# objects. In Go, you do SQL by writing SQL, and you od GRPC by writing protobuf specs.

grey-area•1h ago
There’s probably no deep reason, does it matter much?
torginus•1h ago
Yes it does, function-scope defer needs a dynamic data structure to keep track of pending defers, so its not zero cost.

It can be also a source of bugs where you hang onto something for longer than intended - considering there's no indication of something that might block in Go, you can acquire a mutex, defer the release, and be surprised when some function call ends up blocking, and your whole program hangs for a second.

christophilus•1h ago
I’ve worked with languages that have both, and find myself wishing I could have function-level defer inside conditionals when I use the block-level languages.
gwd•1h ago
So sometimes you want it lexical scope, and sometimes function scope; For example, maybe you open a bunch of files in a loop and need them all open for the rest of the function.

Right now it's function scope; if you need it lexical scope, you can wrap it in a function.

Suppose it were lexical scope and you needed it function scope. Then what do you do?

gf000•1h ago
Making it lexical scope would make both of these solvable, and would be clear for anyone reading it.

You can just introduce a new scope wherever you want with {} in sane languages, to control the required behavior as you wish.

lowmagnet•1h ago
You can start a new scope with `{}` in go. If I have a bunch of temp vars I'll declare the final result outside the braces and then do the work inside. But lately days I'll just write a function. It's clearer and easier to test.
tgv•56m ago
Currently, you can write

    if (some condition) { defer x() }
When it's lexically scoped, you'd need to add some variable. Not that that happens a lot, but a lexically scoped defer isnt needed often either.
masklinn•1h ago
> Suppose it were lexical scope and you needed it function scope. Then what do you do?

Defer a bulk thing at the function scope level, and append files to an array after opening them.

biztos•1h ago
That seems like more work, and less readability, than sticking in the extra function.

Would be nice to have both options though. Why not a “defer” package?

anonymoushn•1h ago
defer { close all the files in the collection }

?

torginus•1h ago
I never wanted function-scope defer, not sure what would be the usecase, but if there was one, you could just do what the other comments suggested.
cabirum•1h ago
Lexical scope does not have a stack to put defer onto.
masklinn•1h ago
All the defer sites in a lexical scope are static, you can target those sites directly or add a fixed-size stack in the frame.
porridgeraisin•1h ago
> Previous posts Why Go is not my favourite language and Go programs are not portable have me critiquing Go for over a decade.

I chuckled

colesantiago•1h ago
Same here, I don't know if this makes him Go's biggest fan or this is actually genuinely sad.

Never had any problems with Go as it makes me millions each year.

neuroelectron•53m ago
Never had a problem with Enron because I sold it when it was high.
jact•1h ago
I worked briefly on extending an Go static site generator someone wrote for a client. The code was very clear and easy to read, but difficult to extend due to the many rough edges with the language. Simple changes required altering a lot of code in ways that were not immediately obvious. The ability to encapsulate and abstract is hindered in the name of “simplicity.” Abstraction is the primary way we achieve simple and easy to extend code. John Ousterhoust defined a complex program as one that is difficult to extend rather than necessarily being large or difficult to understand at scale. The average Go program seems to violate this principle a lot. Programs appear “simple” but extension proves difficult and fraught.

Go is a case of the emperor having no clothes. Telling people that they just don’t get it or that it’s a different way of doing things just doesn’t convince me. The only thing it has going for it is a simple dev experience.

akoboldfrying•1h ago
defer is no worse than Java's try-with-resources. Neither is true RAII, because in both cases you, the caller, need to remember to write the wordy form ("try (...) {" or "defer ...") instead of the plain form ("..."), which will still compile but silently do the wrong thing.
xyzzyz•1h ago
Sure, true RAII would be improvement over both, but the author's point is that Java is an improvement over Go, because the resource acquisition is lexical scoped, not function-scoped. Imagine if Java's `try (...) { }` didn't clear the resource when the try block ends, but rather when the wrapping method returns. That's how Go's defer works.
akoboldfrying•1h ago
Can't you create a new block scope in Go? If not, I agree. If so, just do that if you want lexical scoping?
gf000•38m ago
You have to create an anonymous function.
the_duke•1h ago
I personally don't like Go, and it has many shortcomings, but there is a reason it is popular regardless:

Go is a reasonably performant language that makes it pretty straightforward to write reliable, highly concurrent services that don't rely on heavy multithreading - all thanks to the goroutine model.

There really was no other reasonably popular, static, compiled language around when Google came out.

And there still barely is - the only real competitor that sits in a similar space is Java with the new virtual threads.

Languages with async/await promise something similar, but in practice are burdened with a lot of complexity (avoiding blocking in async tasks, function colouring, ...)

I'm not counting Erlang here, because it is a very different type of language...

So I'd say Go is popular despite the myriad of shortcomings, thanks to goroutines and the Google project street cred.

zwnow•1h ago
What modern language is a better fit for new projects in your opinion?
aloukissas•1h ago
Elixir, with types
sarchertech•1h ago
That doesn’t exist yet. Also Elixir is in no way a replacement for Go.

It can’t match it for performance. There’s no mutable array, almost everything is a linked list, and message passing is the only way to share data.

I primarily use Elixir in my day job, but I just had to write high performance tool for data migration and I used Go for that.

zwnow•1h ago
This one i can get behind.
pmarreck•1h ago
I love Elixir but you cannot compile it into a single binary, it is massively concurrent but single-threaded slow, and deployment is still nontrivial.

And lists are slower than arrays, even if they provide functional guarantees (everything is a tradeoff…)

That said, pretty much everything else about it is amazing though IMHO and it has unique features you won’t find almost anywhere else

agos•1h ago
yeah, if the requirement is "makes it pretty straightforward to write reliable, highly concurrent services that don't rely on heavy multithreading", Elixir is a perfect match.

And even without types (which are coming and are looking good), Elixir's pattern matching is a thousands times better than the horror of Go error handling

gf000•1h ago
For web frontend: js

For ML/data: python

For backend/general purpose software: Java

The only silver bullet we know of is building on existing libraries. These are also non-accidentally the top 3 most popular languages according to any ranking worthy of consideration.

tedk-42•1h ago
I'd swap java with go any day of the week. I never liked how much 'code-padding' is required with java `public static void main`
gf000•1h ago
It's rich to complain about verbosity coming from Go.

Nonetheless, Java has eased the psvm requirements, you don't even have to explicitly declare a class and a void main method is enough. [1] Not that it would matter for any non-script code.

[1] https://openjdk.org/jeps/495

kasperni•1h ago
For Java 25 which is planned to be released in a couple of weeks:

----- https://openjdk.org/jeps/512 -----

First, we allow main methods to omit the infamous boilerplate of public static void main(String[] args), which simplifies the Hello, World! program to:

  class HelloWorld {
    void main() {
      System.out.println("Hello, World!");
    }
  }
Second, we introduce a compact form of source file that lets developers get straight to the code, without a superfluous class declaration:

  void main() {
    System.out.println("Hello, World!"); 
  }
Third, we add a new class in the java.lang package that provides basic line-oriented I/O methods for beginners, thereby replacing the mysterious System.out.println with a simpler form:

  void main() {
    IO.println("Hello, World!");
  }
zwnow•1h ago
Java, lol. Enterprise lang with too many abstractions and wrongly interpreted OOP. Absolutely not.
myaccountonhn•1h ago
What about php/ruby for web?
gf000•1h ago
An expert Ruby programmer can do wonders and be insanely productive, but I think there is a size from which it doesn't scale as nicely (both from a performance and a larger team perspective).

PHP's frameworks are fantastic and they hide a lot from an otherwise minefield of a language (though steadily improved over the years).

Both are decent choices if this is what you/your developers know.

But they wouldn't be my personal first choice.

keb_•17m ago
Absolutely no on Java. Even if the core language has seen improvements over the years, choosing Java almost certainly means that your team will be tied to using proprietary / enterprise tools (IntelliJ) because every time you work at a Java/C# shop, local environments are tied to IDE configurations. Not to mention Spring -- now every code review will render "Large diffs are not rendered by default." in Github because a simple module in Java must be a new class at least >500 LOC long.
gf000•8m ago
When did you last touch java, before 2000?

Local environments are not tied to IDEs at all, but you are doing yourself a disservice if you don't use a decent IDE irrespective of language - they are a huge productivity boost.

And are you stuck in the XML times or what? Spring Boot is insanely productive - just as a fact of matter, Go is significantly more verbose than Java, with all the unnecessary if errs.

gf000•1h ago
> And there still barely is - the only real competitor that sits in a similar space is Java with the new virtual threads

Which Google uses far more commonly than Go, still to this day.

fabian2k•1h ago
There are real pain points with async/await, but I find the criticism there often overblown. Most of the issues go away if you go pure async, mixing older sync code with async is much more difficult though.

My experience is mostly with C#, but async/await works very well there in my experience. You do need to know some basics there to avoid problem, but that's the case for essentially every kind of concurrency. They all have footguns.

cogman10•1h ago
Slowly but surely, the jvm has been closing the go gap. With efforts like virtual threads, zgc, lilliput, Leyden, and Valhalla, the jvm has been closing the gap.

The change from Java 8 to 25 is night and day. And the future looks bright. Java is slowly bringing in more language features that make it quite ergonomic to work with.

theshrike79•1h ago
I'm still traumatised by Java from my earlier career. So many weird patterns, FactoryFactories and Spring Framework and ORMs that work 90% of the time and the 10% is pure pain.

I have no desire to go back to Java no matter how much the language has evolved.

For me C# has filled the void of Java in enterprise/gaming environments.

arethuza•1h ago
To be fair those "weird patterns" weren't really Java itself but the crazy culture that grew up around it when it became "enterprise".
gf000•1h ago
And actually coming over from C++!
pjmlp•49m ago
It is incredible how many people think GoF has Java on it, without ever reading anything about the book.
Orygin•1h ago
Plus it seems hopeful to think you'll be only working with "New java" paradigm when most enterprise software is stuck on older versions. Just like python, in theory you can make great new green field project but 80% of the work in the industry is on older or legacy components.
gf000•12m ago
Yeah, and you might just be given a mainframe with vacuum tubes..

Like, there are 10 million Java devs, there is a whole lot of completely brand new development going in any language, let alone in such a huge one.

CharlieDigital•1h ago
C# is a highly underrated language that has evolved very quickly over the last decade into a nice mix of OOP and functional.

It's fast enough, easy enough (being very similar now to TypeScript), versatile enough, well-documented (so LLMs do a great job), broad and well-maintained first party libraries, and the team has over time really focused on improving terseness of the language (pattern matching and switch expressions are really one thing I miss a lot when switching between C# and TS).

EF Core is also easily one of the best ORMs: super mature, stable, well-documented, performant, easy to use, and expressive. Having been in the Node ecosystem for the past year, there's really no comparison for building fast with less papercuts (Prisma, Drizzle, etc. all abound with papercuts).

It's too bad that it seems that many folks I've chatted with have a bad taste from .NET Framework (legacy, Windows only) and may have previously worked in C# when it was Windows only and never gave it another look.

theshrike79•59m ago
I'm still sad that Silverlight[0] (and Moonlight) died because people hated MS so viscerally back then.

It was actually really good for the time and lightyears ahead of whatever Flash was doing.

But people rather used all kinds of hacks to get Flash working on Linux and OSX rather than use Moonlight.

[0] https://en.wikipedia.org/wiki/Microsoft_Silverlight

torginus•54m ago
While C# is great, but the problem with programming languages, is you're net only picking a language, but a kind of company who uses it, and a kind of person who writes it.

Which means if you write C#, you'll encounter a ton of devs who come from an enterprise, banking or govt background, who think doing a 4 layer enterprise architecture with DTOs and 5 line classes is the only way you can write a CRUD app, and the worst of all you'll se a ton of people who learned C# in college a decade ago and refuse to learn anything else.

EF is great, but most people use it because they don't have to learn SQL and databases.

Blazor is great, but most people use it because they don't want to learn Frontend dev, and JS frameworks.

CharlieDigital•46m ago
I think you have a point with the types of resources, but in my experience, its also not hard to separate the wheat from the chaff with pretty simple heuristics (though that is likely very different now with AI and cheating!).

"Modern C#" (if we can differentiate that) has a lot of nice amenities for modeling like immutable `record` types and named tuples. I think where EF really shines is that it allows you to model the domain with persistence easily and then use DTOs purely as projections (which is how I use DTOs) into views (e.g. REST API endpoints).

I can't say for the broader ecosystem, but at least in my own use cases, EFC is primarily used for write scenarios and some basic read scenarios. But in almost all of my projects, I end up using CQRS with Dapper on the read side for more complex queries. So I don't think that it's people avoiding SQL; rather it's teams focused on productivity first.

WRT to Blazor, I would not recommend it in place of JS except for internal tooling (tried it at one startup and switched to Vue + Vite). But to be fair, modern FE development in JS is an absolute cluster of complexity.

mohaine•1h ago
That isn’t Java, but spring.

That said, if on the JVM, just use Kotlin.

clumsysmurf•1h ago
Being able to create a self contained Kotlin app (JVM) that starts up quickly and uses the same amount of memory as the equivalent golang app would be amazing.
gf000•46m ago
Graal native Image does that (though the compile time is quite long, but you can just run it on the JVM for development with hot reload and whatnot, and only do a native compile at release)
imiric•1h ago
That may be true, but navigating 30 years of accumulated cruft, fragmented ecosystems and tooling, and ever-evolving syntax and conventions, is enough to drive anyone away. Personally, I never want to deal with classpath hell again, though this may have improved since I last touched Java ~15 years ago.

Go, with all its faults, tries very hard to shun complexity, which I've found over the years to be the most important quality a language can have. I don't want a language with many features. I want a language with the bare essentials that are robust and well designed, a certain degree of flexibility, and for it to get out of my way. Go does this better than any language I've ever used.

gf000•52m ago
I can reasonably likely run a 30 years old compiled, .jar file on the latest Java version. Java is the epitome of backwards and forward-compatible changes, and the language was very carefully grown so the syntax is not too indifferent, someone hibernated since Java 7 will probably have no problem reading Java 25 code.

> Go, with all its faults, tries very hard to shun complexity

The whole field is about managing complexity. You don't shun complexity, you give tools to people to be able to manage it.

And Go goes the low end of the spectrum, of not giving enough features to manage that complexity -- it's simplistic, not simple.

I think the optimum as actually at Java - it is a very easy language with not much going on (compared to, say, Scala), but just enough expressivity that you can have efficient and comfortable to use libraries for all kind of stuff (e.g. a completely type safe SQL DSL)

imiric•5m ago
> The whole field is about managing complexity. You don't shun complexity, you give tools to people to be able to manage it.

Complexity exists in all layers of computing, from the silicon up. While we can't avoid complexity of real world problems, we can certainly minimize the complexity required for their solutions. There are an infinite amount of problems caused primarily by the self-induced complexity of our software stacks and the hardware it runs on. Choosing a high-level language that deliberately tries to avoid these problems is about the only say I have in this matter, since I don't have the skill nor patience to redo decades of difficult work smarter people than me have done.

Just because a language embraces simplicity doesn't mean that it doesn't provide the tools to solve real world problems. Go authors have done a great job of choosing the right set of trade-offs, unlike most other language authors.

positron26•1h ago
Count Rust. From what I can see, it's becoming very popular in the microservices landscape. Not hard to imagine why. Multithreading is a breeze. Memory use is low. Latency is great.
theshrike79•1h ago
The comparative strictness and simplicity of Go also makes it a good option for LLM-assisted programming.

Every single piece of Go 1.x code scraped from the internet and baked in to the models is still perfectly valid and compiles with the latest version.

jonathan920•1h ago
Oh no , Rust is too tough, go is no good, am i going back to java?
maxloh•1h ago
Maybe the new in-development Carbon language? It sounds promising, but it is nowhere near its 1.0 release.
masklinn•1h ago
Carbon exists only for interoperating with and transitioning off of C++. Creating a new code base in carbon doesn’t really make sense, and the project’s readme literally tells you not to do that.
maxloh•1h ago
> ... and the project’s readme literally tells you not to do that.

Could you quote which paragraph you're talking about?

AFAIK, interoperability with C++ code is just one of their explicit goals; they only place that as the last item in the "Language Goals" section.

masklinn•10m ago
> Existing modern languages already provide an excellent developer experience: Go, Swift, Kotlin, Rust, and many more. Developers that can use one of these existing languages should.
pjmlp•1h ago
So many options in-between.
antiquark•1h ago
I'm still appalled that there's no "do while" loop in go.
pansa2•1h ago
Python doesn’t have one either
zwnow•1h ago
> Wait, what? Why is err reused for foo2()? Is there’s something subtle I’m not seeing? Even if we change that to :=, we’re left to wonder why err is in scope for (potentially) the rest of the function. Why? Is it read later?

First time its assigned nil, second time its overwritten in case there's an error in the 2nd function. I dont see the authors issue? Its very explicit.

thomashabets2•53m ago
Author here: I'm not talking about the value. I'm talking about the lifetime of the variable.

After checking for nil, there's no reason `err` should still be in scope. That's why it's recommended to write `if err := foo(); err != nil`, because after that, one cannot even accidentally refer to `err`.

I'm giving examples where Go syntactically does not allow you to limit the lifetime of the variable. The variable, not its value.

You are describing what happens. I have no problem with what happens, but with the language.

zwnow•48m ago
Why does the lifetime even matter?
thomashabets2•21m ago
I gave an example in the post, but to spell it out: Because a typo variable is not caught, e.g. as an unused variable.

The example from the blog post would fail, because `return err` referred to an `err` that was no longer in scope. It would syntactically prevent accidentally writing `foo99()` instead of `err := foo99()`.

lowmagnet•53m ago
I'll have to read the rest later but this was an unforced error on the author's part. There is nothing unclear about that block of code. If err isn't but, it was set, and we're no longer in the function. If it's not, why waste an interface handle?
crinkly•1h ago
I dislike Go but I haven’t found anything else I dislike less.
slackfan•1h ago
Still better (compiler speed) than Rust.
gf000•1h ago
Still not playing remotely in the same league. Only one of them is a "systems language", reusing Go's inappropriate marketing term.
gwd•1h ago
Anyone want to try to explain what he's on about with the first example?

    bar, err := foo()
    if err != nil {
      return err
    }
    if err := foo2(); err != nil {
      return err
    }
The above (which declares a new value of err scoped to the second if statement) should compile right? What is it that he's complaining about?

EDIT: OK, I think I understand; there's no easy way to have `bar` be function-scoped and `err` be if-scoped.

I mean, I'm with him on the interfaces. But the "append" thing just seems like ranting to me. In his example, `a` is a local variable; why would assigning a local variable be expected to change the value in the caller? Would you expect the following to work?

    int func(a *MyStruct) {
      a = &MyStruct{...}
    }
If not why would you expect `a = apppend(a, ...)` to work?
terminalbraid•1h ago
You didn't copy the code correctly from the first example.
gwd•1h ago
Well no, the second "if" statement is a red herring. Both of the following work:

    bar, err := foo()
    if err != nil {
      return err
    }
    if err = foo2(); err != nil {
      return err
    }
and

    bar, err := foo()
    if err != nil {
      return err
    }
    if err := foo2(); err != nil {
      return err
    }
He even says as much:

> Even if we change that to :=, we’re left to wonder why err is in scope for (potentially) the rest of the function. Why? Is it read later?

My initial reaction was: "The first `err` is function-scope because the programmer made it function-scope; he clearly knows you can make them local to the if, so what's he on about?`

It was only when I tried to rewrite the code to make the first `err` if-scope that I realized the problem I guess he has: OK, how do you make both `err` variable if-scope while making `bar` function-scope? You'd have to do something like this:

    var bar MyType
    if lbar, err := foo(); err != nil {
      return err
    } else {
      bar = lbar
    }
Which is a lot of cruft to add just to restrict the scope of `err`.
sublimefire•1h ago
edit: the main rant about err was that it is left in scope but I believe the author does not like that
mrweasel•1h ago
That might be it, but I wondered about that one, as well as the append complaint. It seems like the author disagree with scoping rules, but they aren't really any different than a lot of other languages.

If someone really doesn't like the reuse of err, there's no reason why they couldn't create separate variable, e.g. err_foo and err_foo2. There's not no reason to not reuse err.

thomashabets2•51m ago
> why would assigning a local variable be expected to change the value in the caller?

I think you may need to re-read. My point is that it DOES change the value in the caller. (well, sometimes) That's the problem.

sublimefire•1h ago
This post is just an attention grabbing rage bate. Listed issues are superficial unless the person is a bit far into the spectrum. There is no good datapoint which would weigh the issues against real world problems, i.e. how much does it cost. Even the point about ram is weak without the data.
fschuett•1h ago
Technically, the term "billion dollar mistake", coined in 1965, would now be a "10 billion dollar mistake" in 2025. Or, if the cost is measured in terms of housing, it would be a "21 billion dollar mistake".

:^/

YetAnotherNick•1h ago
What does this mean? Do they just use recover and keep bad data?

> The standard library does that. fmt.Print when calling .String(), and the standard library HTTP server does that, for exceptions in the HTTP handlers.

Apart from this most doesn't seem that big of a deal, except for `append` which is truly a bad syntax. If you doing it inplace append don't return the value.

andy_ppp•1h ago
They are forcing people to write Typescript code like it’s Golang where I am right now (amongst other extremely stupid decisions - only unit test service boundaries, do not pull out logic into pure functions, do not write UI tests, etc.). I really must remember to ask organisations to show me their code before joining them.

(I realise this isn’t who is hiring, but email in bio)

theshrike79•1h ago
Have you seen Java people write Python? Same vibe :)
keb_•15m ago
Reminded me of this classic talk https://www.youtube.com/watch?v=o9pEzgHorH0
sebstefan•1h ago
Ah yes. I love working at places that hire experts just to tell them how they should do the work they're an expert at.
candiddevmike•1h ago
I do this and think it works really well...

myfunc(arg: string): Value | Err

I really try not to throw anymore with typescript, I do error checking like in Go. When used with a Go backend, it makes context switching really easy...

commandersaki•1h ago
“What color is your nil?” — The two billion dollar mistake.

Talk about hyperbole.

lvl155•1h ago
I think a lot of people got on the Go train because of Google and not necessarily because it was good. There was a big adoption in Chinese tech scene for example. I personally think Rust/Go/Zig and other modern languages suffer a bit from trying too hard not to be C/C++/Java.
wewxjfq•42m ago
Go was a breath of fresh air and pretty usable right from the start. It felt like a neat little language with - finally - a modern standard library. Fifteen years ago, that was a welcome change. I think it's no surprise that Go and Node.js both got started and took off around the same time. People were looking something modern, lightweight, and simple and both projects delivered that.
813ac4312b25c•1h ago
> Probably [hello NIGHTMARE !]. Who wants that? Nobody wants that.

I don't really care if you want that. Everyone should know that that's just the way slices work. Nothing more nothing less.

I really don't give a damn about that, i just know how slices behave, because I learned the language. That's what you should do when you are programming with it (professionally)

terminalbraid•1h ago
If you're fine with that then you should be upset by the subsequent example, because by your own definition "that's just not the way slices work".
813ac4312b25c•1h ago
I am fine with the subsequent example, too. If you read up about slices, then that's how they are defined and how they work. I am not judging, I am just using the language as it is presented to me.

For anyone interested, this article explains the fundamentals very well, imo: https://go.dev/blog/slices-intro

terminalbraid•1h ago
Then you seem to be fine with inconsistent ownership and a behavioral dependence on the underlying data rather than the structure.

You really don't see why people would point a definition that changes underneath you out as a bad definition? They're not arguing the documentation is wrong.

assbuttbuttass•58m ago
The definition is perfectly consistent. append is in-place if there's enough capacity (and the programmer can check this directly with cap() if they want), and otherwise it allocates a new backing array.
terminalbraid•54m ago
Yes, it's consistent and complicated and non-intuitive.

"Consistent" is necessary but not sufficient for "good".

thomashabets2•1h ago
Yup. If you code in Go then you should know that.

Just like every PHP coder should know that the ternary operator associativity is backwards compared to every other language.

If you code in a language, then you should know what's bad about that language. That doesn't make those aspects not bad.

skitter•53m ago
The author obviously knows that too, otherwise they wouldn't have written about it. All of these issues are just how the language works, and that's the problem.
pjmlp•1h ago
As usual, lets revisit something that Pascal could do in 1976,

    type

    StatusCodes = (Success, Ongoing, Done)
Go in 2025,

    type StatusCodes int

    const (
        Success StatusCodes = iota
        Ongoing
        Done
    )
thiht•1h ago
Where's Pascal today?
terminalbraid•1h ago
Just below Go with Perl in between. All above Fortran, all below Visual Basic.

https://www.tiobe.com/tiobe-index/

ofrzeta•1h ago
It's alive and kicking, right? :) https://www.freepascal.org They even have a game engine that can compile to a WASM target: https://castle-engine.io/web
dardeaup•1h ago
Ouch!! Pascal's lack of popularity certainly isn't due to the fact that it supports such nice enumerated types (or sets for that matter). I think he was just pointing out that such nice things have existed (and been known to exist) for a long time and that it's odd that a new language couldn't have borrowed the feature.
pjmlp•1h ago
Being used by these folks, https://www.embarcadero.com/

If you prefer, I can provide the same example in C, C++, D, Java, C#, Scala, Kotlin, Swift, Rust, Nim, Zig, Odin.

813ac4312b25c•1h ago
The absolutely pointless and ridiculous complaints about enums are just plain stupid by this point.

Ok we get it, you want something fancier. Well, you didn't get it. Deal with it. Go has other problems (as pointed out by the OP). I really don't understand how people could care so much about this enum thing. Yes, Rust enums are great, but they are just completely different. Why would I ever compare them and waste energy on that? Different designers, different decisions.

pjmlp•1h ago
Rust did not exist in 1976.
torginus•1h ago
Where do you put the comments on the Pascal version?
pjmlp•1h ago
Where you feel like it.
ochronus•1h ago
s/good/perfect
porridgeraisin•1h ago
I wrote a small explainer on the typed-vs-untyped nil issue. It is one of the things that can actually bite you in production. Easy to miss it in code review.

Here's the accompanying playground: https://go.dev/play/p/Kt93xQGAiHK

If you run the code, you will see that calling read() on ControlMessage causes a panic even though there is a nil check. However, it doesn't happen for Message. See the read() implementation for Message: we need to have a nil check inside the pointer-receiver struct methods. This is the simplest solution. We have a linter for this. The ecosystem also helps, e.g protobuf generated code also has nil checks inside pointer receivers.

xlii•1h ago
After spending some time in lower level languages Go IMO makes much more sense. Your example:

First one - you have an address to a struct, you pass it, all good.

Second case: you set address of struct to "nil". What is nil? It's an address like anything else. Maybe it's 0x000000 or something else. At this point from memory perspective it exists, but OS will prevent you from touching anything that NULL pointer allows you to touch.

Because you don't touch ANYTHING nothing fails. It's like a deadly poison in a box you don't open.

Third example id the same as second one. You have a IMessage but it points to NULL (instead NULL pointing to deadly poison).

And in fourth, you finally open the box.

Is it magic knowledge? I don't think so, but I'm also not surprised about how you can modify data through slice passing.

IMO the biggest Go shortcoming is selling itself as a high level language, while it touches more bare metal that people are used to touch.

beanjuiceII•54m ago
great example, that is indeed tricky
gnfargbl•1h ago
As a long-time Go programmer I didn't understand the comment about two types of nil because I have never experienced that issue, so I dug into it.

It turns out to be nothing but a misunderstanding of what the fmt.Println() statement is actually doing. If we use a more advanced print statement then everything becomes extremely clear:

    package main

    import (
      "fmt"
      "github.com/k0kubun/pp/v3"
    )

    type I interface{}
    type S struct{}

    func main() {
      var i I
      var s *S

      pp.Println(s, i)                        // (*main.S)(nil) nil
      fmt.Println(s == nil, i == nil, s == i) // true true false

      i = s

      pp.Println(s, i)                        // (*main.S)(nil) (*main.S)(nil)
      fmt.Println(s == nil, i == nil, s == i) // true false true
    }
The author of this post has noted a convenience feature, namely that fmt.Println() tells you the state of the thing in the interface and not the state of the interface, mistaken it as a fundamental design issue and written a screed about a language issue that literally doesn't exist.

Being charitable, I guess the author could actually be complaining that putting a nil pointer inside a nil interface is confusing. It is indeed confusing, but it doesn't mean there are "two types" of nil. Nil just means empty.

thomashabets2•58m ago
Author here. No, I didn't misunderstand it. Interface variables have two types of nil. Untyped, which does compare to nil, and typed, which does not.

What are you trying to clarify by printing the types? I know what the types are, and that's why I could provide the succinct weird example. I know what the result of the comparisons are, and why.

And the "why" is "because there are two types of nil, because it's a bad language choice".

I've seen this in real code. Someone compares a variable to nil, it's not, and then they call a method (receiver), and it crashes with nil dereference.

Edit, according to this comment this two-types-of-null bites other people in production: https://news.ycombinator.com/item?id=44983576

gnfargbl•26m ago
> Author here. No, I didn't misunderstand it. Interface variables have two types of nil. Untyped, which does compare to nil, and typed, which does not.

There aren't two types of nil. Would you call an empty bucket and an empty cup "two types of empty"?

There is one nil, which means different things in different contexts. You're muddying the waters and making something which is actually quite straightforward (an interface can contain other things, including things that are themselves empty) seem complicated.

> I've seen this in real code. Someone compares a variable to nil, it's not, and then they call a method (receiver), and it crashes with nil dereference.

Sure, I've seen pointer-to-pointer dereferences fail for the same reason in C. It's not particularly different.

tux3•49m ago
The author is showing the result of s==nil and i==nil, which are checks that you would have to do almost everywhere (the so called "billion dollar mistake")

It's not about Printf. It's about how these two different kind of nil values sometimes compare equal to nil, sometimes compare equal to each other, and sometimes not

Yes there is a real internal difference between the two that you can print. But that is the point the author is making.

gnfargbl•20m ago
It's a contrived example which I have never really experienced in my own code (and at this point, I've written a lot of it) or any of my team's code.

Go had some poor design features, many of which have now been fixed, some of which can't be fixed. It's fine to warn people about those. But inventing intentionally confusing examples and then complaining about them is pretty close to strawmanning.

tux3•9m ago
I believe you that you've never hit it, it's definitely not an everyday problem. But they didn't make it up, it does bite people from time to time.

It's sort of a known sharp edge that people occasionally cut themselves on. No language is perfect, but when people run into them they rightfully complain about it

bfrog•1h ago
Go nearly gave me carpal tunnel with the vast quantities and almost the same but not quite the same repetitive code patterns it brings along with it. I’d never use it again.
spicyusername•1h ago
A popular language is always going to attract some hate. Also, these kinds of discussions can be useful for helping the language evolve.

But everyone knows in their heart of hearts that a few small language warts definitely don't outweigh Go's simplicity and convenience. Do I wish it had algebraic data types, sure, sure. Is that a deal-breaker, nah. It's the perfect example of something that's popular for a reason.

It is easily one of the most productive languages. No fuss, no muss, just getting stuff done.

rand0m4r•1h ago
This was an interesting read and very educational in my case, but each time I read an article criticizing a programming language it's written by someone who hasn't done anything better.

It's a shame because it is just as effective as pissing in the wind.

terminalbraid•47m ago
If you're saying someone can't credibly criticize a language without having designed a language themselves, I'll ask that you present your body of work of programming language criticisms so I know if you have "produced something better" in the programming language criticism space.

Of course, by your reasoning this also means you yourself have designed a language.

I'll leave out repeating your colorful language if you haven't done any of these things.

voodooEntity•1h ago
As someone who for >10 years writes golang and has written some bigger codebases using it, this are my takes on this articles claims:

:Error variable Scope -> Yes can be confusing at the beginning, but if you have some experience it doesnt really matter. Would it be cool to scope it down?`Sure, but it feels like here is something blown up to an "issue" where i would see other things to alot more important for the go team to revisit. Regarding the error handling in go, some hate it , some love it : i personally like it (yes i really do) so i think its more a preference than a "bad" thing.

:Two types of nil -> Funny, i never encountered this in > 10 years of go with ALOT of work in pointer juggling, so i wonder in which reality this hits your where it cant be avoided. Tho confusing i admit

:It’s not portable -> I have no opinion here since i work on unix systems only and i have my compiled binaries specific shrug dont see any issue here either.

:append with no defined ownership -> I mean... seriously? Your test case, while the results may be unexpected, is a super wierd one. Why you you append a mid field, if you think about what these functions do under the hood your attemp actualyl feels like you WANT to procude strange behaviour and things like that can be done in any language.

:defer is dumb -> Here i 100% agree - from my pov it leads to massive resource wasting and in certain situations it can also create strange errors, but im not motivated to explain this - ill just say defer, while it seems usefull, from my pov is a bad thing and should not be used.

:The standard library swallows exceptions, so all hope is lost -> "So all hope is lost" i mean you already left the realm of objectiveness long before tbut this really tops it. I wrote some quite big go applications and i never had a situation where i could not handle an exception simply by adjusting my code in a way that i prevent it from even happening. Again - i feel like someone is just in search of things to complain that could simply be avoided. (also in case someone comes up with a super specific probably once in a million case, well alrways keep in mind that language design doesnt orient on the least occuring thing).

:Sometimes things aren’t UTF-8 -> I wont bother to read another whole article, if its important include an example. I have dealth with different encodings (web crawler) and i could handle all of them.

:Memory use -> What you describe is one of the design decisions im not absolutly happy with, the memory handling. But than, one of my golang projects is an in memory graph storage/database - which in one of my cases run for ~2years without restart and had about 18GB of dataset stored in it. It has a lot of mutex handling (regarding your earlier complain with exxceptions, never had one) and it btw run as backend of a internet facing service so it wasnt just fed internal data.

--------------------

Finally i wanne say : often things come down to personal preference. I could spend days raging about javascript, java, c++ or some other languages, but whatfor? Pick the language that fits your use case and your liking, dont pick one that doesnt and complain about it.

Also , just to show im not just a big "golang is the best" fanboy, because it isnt - there are things to critizize like the previously mentioned memory handling.

While i still think you just created memory leaks in your app, golang had this idea of "arenas" which would enable the code to manage memory partly himself and therefor developt much more memory efficient applications. This has stalled lately and i REALLY hope the go team will pick it up again and make this a stable thing to use. I probably would update all of my bigger codebases using it.

Also - and thats something thats annoying me ALOT beacuse it made me spend alot of hours - the golang plugin system. I wrote an architecture to orchestrate processing and for certain reasons i wanted to implement the orchestrated "things" as plugins. But the plugin system as it is rn can only be described as the torments of hell. I messed with it for like 3 years till i recently dropped the plugin functionality and added the stuff directly. Plugins are a very powerfull thing and a good plugin system could be a great thing, but in its current state i would recommend noone to touch it.

These are just two points, i could list some more but the point i want to get to is : there are real things you can critizize instead of things that you create yourself or that are language design decision that you just dont like. Im not sure if such articles are the rage of someone who just is bored or its ragebait to make people read it. Either way its not helping anyone.

thomashabets2•39m ago
Author here.

:Two types of nil

Other commenters have. I have. Not everyone will. Doesn't make it good.

:append with no defined ownership

I've seen it. Of course one can just "not do that", but wouldn't it be nice if it were syntactically prevented?

:It’s not portable ("just Unix")

I also only work on Unix systems. But if you only work on amd64 Linux, then portability is not a concern. Supporting BSD and Linux is where I encounter this mess.

:All hope is lost

All hope is lost specifically on the idea of not needing to write exception safe code. If panics did always crash the problem, then that'd be fine. But no coding standard can save you from the standard library, so yes, all hope about being able to pretend panic exits the problem, is lost.

You don't need to read my blog posts. Looking forward to reading your, much better, critique.

elktown•54m ago
Is there anything that soothes devs more than developing a superiority complex of their particular tooling? And then the unquenchable thirst to bash "downwards"? I find it so utterly pathetic.
0x000xca0xfe•46m ago
> If you stuff random binary data into a string, Go just steams along, as described in this post.

> Over the decades I have lost data to tools skipping non-UTF-8 filenames. I should not be blamed for having files that were named before UTF-8 existed.

Umm.. why blame Go for that?

thomashabets2•23m ago
Author here.

What I intended to say with this is that ignoring the problem if invalid UTF-8 (could be valid iso8859-1) with no error handling, or other way around, has lost me data in the past.

Compare this to Rust, where a path name is of a different type than a mere string. And if you need to treat it like a string and you don't care if it's "a bit wrong" (because it's for being shown to the user), then you can call `.to_string_lossy()`. But it's be more hard to accidentally not handle that case when exact name match does matter.

When exactness matters, `.to_str()` returns `Option<&str>`, so the caller is forced to deal with the situation that the file name may not be UTF-8.

Being sloppy with file name encodings is how data is lost. Go is sloppy with strings of all kinds, file names included.

quectophoton•41m ago
In practice, none of these thing mentioned in the article have been an issue for me, at all. (Upvoted anyway)

What has been an issue for me, though, is working with private repositories outside GitHub (and I have to clarify that, because working with private repositories on GitHub is different, because Go has hardcoded settings specifically to make GitHub work).

I had hopes for the GOAUTH environment variable, but either (1) I'm more dumb and blind than I thought I already was, or (2) there's still no way to force Go to fetch a module using SSH without trying an HTTPS request first. And no, `GOPRIVATE="mymodule"` and `GOPROXY="direct"` don't do the trick, not even combined with Git's `insteadOf`.

naikrovek•39m ago
Show me a programming language that does not have annoying flaws and I'll show you a programming language that does not yet exist, and probably won't ever exist.

I really like Go. It scratches every itch that I have. Is it the language for your problems? I don't know, but very possibly that answer is "no".

Go is easy to learn, very simple (this is a strong feature, for me) and if you want something more, you can code that up pretty quickly.

The blog article author lost me completely when they said this:

> Why do I care about memory use? RAM is cheap.

That is something that only the inexperienced say. At scale, nothing is cheap; there is no cheap resource if you are writing software for scale or for customers. Often, single bytes count. RAM usage counts. CPU cycles count. Allocations count. People want to pretend that they don't matter because it makes their job easier, but if you want to write performant software, you better have that those cpu cache lines in mind, and if you have those in mind, you have memory usage of your types in mind.

xlii•34m ago
I don't agree with most of the article but I believe I know where it comes from.

Golang's biggest shortcoming is the fact that it touches bare metal isn't visible clearly enough. It provides many high level features which makes this ambience of "we got you" but fails on delivering proper education to its users that they are going to have a dirt on their hands.

Take a slice for example: even in naming it means "part of" but in reality it's closer to "box full of pointers" what happens when you modify pointer+1? Or "two types of nil"; there is a difference between having two bytes (simplification), one of struct type and the other of address to that struct and having just a NULL - same as knowing that house doesn't exist and being confident that house exists and saying it's in the middle of the volcano beneath the ocean.

The Foo99 critique is another example. If you'd want to have not 99 loop but 10 billion loops each with mere 10 bytes you'd need 100GiB of memory just to exit it. If you'd reuse the address block you'd only use... 10 bytes.

I also recommend trying to implement lexical scope defer in C and putting them in threads. That's a big bottle of fun.

I think that it ultimately boils down to what kind of engineer one wants to be. I don't like hand holding and rather be left on my own with a rain of unit tests following my code so Go, Zig, C (from low level Languages) just works for me. Some prefer Rust or high level abstractions. That's also fine.

But IMO poking at Go that it doesn't hide abstractions is like making fun of football of being child's play because not only it doesn't have horses but also has players using legs instead of mallets.

abtinf•10m ago
Go has problems, sure. But I’ve yet to see a hit piece on Go that actually holds up to real scrutiny.

Usually, as here, objections to go take the form a technically-correct-but-ultimately-pedantic arguments.

The positives of go are so overwhelmingly high magnitude that all those small things basically don’t matter enough to abandon the language.

Go is good enough to justify using it now while waiting for the slow-but-steady stream of improvements from version to version to make life better.

The Management Skill Nobody Talks About

https://terriblesoftware.org/2025/08/22/the-management-skill-nobody-talks-about/
58•matheusml•45m ago•15 comments

Io_uring, kTLS and Rust for zero syscall HTTPS server

https://blog.habets.se/2025/04/io-uring-ktls-and-rust-for-zero-syscall-https-server.html
296•guntars•9h ago•55 comments

What about using rel="share-url" to expose sharing intents?

https://shkspr.mobi/blog/2025/08/what-about-using-relshare-url-to-expose-sharing-intents/
24•edent•1h ago•6 comments

What the Hell Is Going On?

https://catskull.net/what-the-hell-is-going-on-right-now.html
101•todsacerdoti•6h ago•31 comments

LabPlot: Free, open source and cross-platform Data Visualization and Analysis

https://labplot.org/
48•turrini•4h ago•7 comments

DeepSeek-v3.1

https://api-docs.deepseek.com/news/news250821
600•wertyk•18h ago•177 comments

Launch HN: Inconvo (YC S23) – AI agents for customer-facing analytics

3•ogham•37m ago•0 comments

Everything Is Correlated

https://gwern.net/everything
171•gmays•11h ago•72 comments

Control shopping cart wheels with your phone (2021)

https://www.begaydocrime.com/
203•mystraline•12h ago•71 comments

Code formatting comes to uv experimentally

https://pydevtools.com/blog/uv-format-code-formatting-comes-to-uv-experimentally/
296•tanelpoder•17h ago•185 comments

An interactive guide to SVG paths

https://www.joshwcomeau.com/svg/interactive-guide-to-paths/
363•joshwcomeau•3d ago•35 comments

Weaponizing image scaling against production AI systems

https://blog.trailofbits.com/2025/08/21/weaponizing-image-scaling-against-production-ai-systems/
424•tatersolid•1d ago•122 comments

Crimes with Python's Pattern Matching (2022)

https://www.hillelwayne.com/post/python-abc/
217•agluszak•17h ago•87 comments

From GPT-4 to GPT-5: Measuring progress through MedHELM [pdf]

https://www.fertrevino.com/docs/gpt5_medhelm.pdf
111•fertrevino•14h ago•83 comments

How does the US use water?

https://www.construction-physics.com/p/how-does-the-us-use-water
189•juliangamble•1d ago•150 comments

1981 Sony Trinitron KV-3000R: The Most Luxurious Trinitron [video]

https://www.youtube.com/watch?v=jHG_I-9a7FY
73•ksec•1d ago•52 comments

Building AI products in the probabilistic era

https://giansegato.com/essays/probabilistic-era
158•sdan•18h ago•91 comments

AWS CEO says using AI to replace junior staff is 'Dumbest thing I've ever heard'

https://www.theregister.com/2025/08/21/aws_ceo_entry_level_jobs_opinion/
1455•JustExAWS•1d ago•617 comments

Being confidently wrong is holding AI back

https://promptql.io/blog/being-confidently-wrong-is-holding-ai-back
64•tango12•1h ago•95 comments

Show HN: OS X Mavericks Forever

https://mavericksforever.com/
365•Wowfunhappy•3d ago•156 comments

My other email client is a daemon

https://feyor.sh/blog/my-other-email-client-is-a-mail-daemon/
172•aebtebeten•1d ago•22 comments

Beyond sensor data: Foundation models of behavioral data from wearables

https://arxiv.org/abs/2507.00191
218•brandonb•22h ago•47 comments

How well does the money laundering control system work?

https://www.journals.uchicago.edu/doi/10.1086/735665
251•PaulHoule•1d ago•288 comments

Elegant mathematics bending the future of design

https://actu.epfl.ch/news/elegant-mathematics-bending-the-future-of-design/
130•robinhouston•3d ago•13 comments

AI tooling must be disclosed for contributions

https://github.com/ghostty-org/ghostty/pull/8289
655•freetonik•18h ago•397 comments

Using Podman, Compose and BuildKit

https://emersion.fr/blog/2025/using-podman-compose-and-buildkit/
279•LaSombra•1d ago•102 comments

Scientists No Longer Find X Professionally Useful, and Have Switched to Bluesky

https://academic.oup.com/icb/advance-article-abstract/doi/10.1093/icb/icaf127/8196180?redirectedFrom=fulltext&login=false
128•sebg•15h ago•98 comments

Benchmarks for Golang SQLite Drivers

https://github.com/cvilsmeier/go-sqlite-bench
85•cvilsmeier•3d ago•24 comments

Privately-Owned Rail Cars

https://www.amtrak.com/privately-owned-rail-cars
156•jasoncartwright•1d ago•245 comments

Miles from the ocean, there's diving beneath the streets of Budapest

https://www.cnn.com/2025/08/18/travel/budapest-diving-molnar-janos-cave
133•thm•3d ago•32 comments