upvote
Exactly. 95% of programmers are application programmers - they ship software used by regular users. I think it's insane to use a non-GC language for most of those cases. Manual memory management is mentally taxing and it's easy to make catastrophic mistakes. The marginal benefit from it is just not worth it unless you're making games or a trading system.

5% who write tools or other "infra" layer for the other 95% to work on top of maybe need that level of control over memory. It doesn't make any sense to me to sign up for that complexity unless you really really need it.

reply
Maybe I'm misunderstanding something but non-GC language doesn't mean you have to do memory management manually? I mean, for example, in Rust (or modern C++), it's basically automatic. There is no mental tax or catastrophic mistakes as far as I know.
reply
Ok.

https://rust-unofficial.github.io/too-many-lists/

I'm not saying Rust is worse than Go. It obviously isn't. But this argument that Rust's memory management isn't more cognitively demanding than Go's memory management --- that isn't true.

reply
Certainly you pay a price for lifetimes but you buy compile time race condition detection via the borrow checker's aliasing-xor-mutability enforcement. So all that is happening is the complexity of concurrency is being made explicit and therefore easier to reason about. Many applications can be architected in a way that wouldn't ever trigger a race, so for people working on that it isn't something they would need to reason about and they can call it unneeded complexity. This is the simpler vs. simplistic distinction also made in the article. If you can be simplistic, garbage collection is less cognitively demanding, but if you are designing race free algorithms with shared memory then rust will be. I do believe more developers and applications live in the former.

The better example actually comes from the article: returning a struct and an iterator over that struct isn't possible in rust. Heck, initializing a struct to return an iterator might lead to issues. Most people will encounter this before needing a linked list and the lesson it teaches will help out with the linked list.

reply
Rust doesn't promise that your safe Rust doesn't have race conditions only specifically that it doesn't have the one very weird kind of race condition from computers with no analogue to the real world, a Data Race.

An ordinary race condition would be e.g. you put the cat out of the front door, then you walk to the kitchen and close that door - well, the cat might race around the outside of the house and get in first. Our world has race conditions, Rust doesn't solve them, take appropriate care.

A data race is much stranger, it's caused by a difference between how humans think about programming ("Sequential consistency" ie time's arrow X causes Y, therefore Y happens after X) and how the machine works (a modern multi-core computer does not exhibit this consistency) maybe you and your house mate both pick up the cat and she tries to put it out the kitchen door, you try to put it out the front door, this seems to work fine mostly but then on Tuesday the cat explodes, everything is covered in cat fur, messy. Rust actually has a whole layer of extra stuff beyond the aliasing-XOR-mutability to prevent this mistake because humans struggle to reason properly about software which loses sequential consistency so it almost doesn't matter what it "means" if this is lost.

reply
> In logic, equivocation ("calling two different things by the same name") is an informal fallacy resulting from [...] knowingly and deliberately using words in a different sense than the one the audience will understand.

Of course I mean data race, most people in such a thread will implicitly understand that is the race meant. Nobody building a webshop with limited supplies wants to prevent "first come first served", it barely makes sense to think about preventing that kind of race

Data races have obvious real world analogues, they are just so obvious people naturally synchronize. You can look over someone's shoulder while they update a paper master copy and observe data tearing as they erase a field and start writing in another value while that is inconsistent with the rest of the form. It is easy to see that data is being modified and wait until the writer is complete instead of memorizing a partial update and walking away to make decisions on the basis of the incomplete information. A good mutex/rwlock is like having a private separate room to go into to make the update so that no overeager person can even observe the partial update (some languages have non callback style mutexes so there the mutex/lock is the analogue of the visual cue that someone is performing the update). I don't find this at all strange to consider. In a concurrent system it is just all too easy to forget that there are other threads (analogue of people) reading/modifying at the same time. So rust makes that manifest through the borrow checker and it becomes obvious.

Rust prevents more than just data races. Even in single threaded code, if you have a reference to a struct (without explicitly choosing interior mutability), you are guaranteed that its value has not changed since the last time you read it, despite other parts of the code having a reference to it. You don't need to make defensive copies. Some people may find this useful, but generally it won't be enough to convince someone to drop their current language in favor of rust. This transfers into multi-threaded code as well: only a single thread can make modifications to a struct through a reference xor as many threads as you want can read from the struct with references. You can easily write go/java/python programs that have these features and so don't feature data races, but they are difficult to reason about: how do you know that there is only a single reference featuring mutation or many threads only reading? The answer requires non-local knowledge which is difficult to reason about and this is enough for some people to consider rust where the answer is local (defined by the variable).

reply
> But this argument that Rust's memory management isn't more cognitively demanding than Go's memory management --- that isn't true.

It's not far from true. The fights you get into with the borrow checker can be legendary, but lifetimes serve more as gentle reminders. If you get stuck, you can always just use Rc, which is pretty close to opt-in GC. But it's rare to have to resort to Rc, because ownership is just not that much of a problem. In fact, I very rarely use Box either. All heap memory allocation is done by containers, not manually by me. I guess the main friction point for lifetimes is Rust's closures and async, but if you avoid them life is pretty simple.

In return for wearing this almost not a problem, you almost don't have to think about releasing a whole pile of other things - like closing files, sockets, and locks. They are guaranteed to be released by the same mechanism.

On balance, I would not be surprised if the cognitive balance tips Rust's way once you allow for the fact that Rust's memory management also gives you robust resource management for free.

reply
How is Aria's linked list document relevant on this topic? Go is the kind of language where they'd call their growable array type "List" because why not. C# did that in fact, when it gained generics they named their generic growable array List<T>

So the linked list is a thing Go doesn't have at all, in Go the equivalent document probably just reminds you of Go's rule "Don't be clever". Thanks Go, I'll keep it in mind.

Generally the argument is that non-GC languages require you to worry about memory management because of Use-after-free, but of course safe Rust just won't compile if you wrote a typical use-after-free so that's not really extra cognitive demand.

reply
You seem to imply that it doesn’t have any cost. It does. You have to make decisions and, in the case of C++: sometimes you have to deal with a lot of really ugly code to make it “automatic”. And if you really have to count bytes and carefully manage stack sizes because you are writing code for a constrained device, you have to pay even more attention than you would in C.

GC’ed languages have memory related challenges too. But it simply isn’t true that these are on the same order of difficulty as the difficulties that do arise in C++.

reply
Yeah, I shouldn't have mentioned C++, it was a bad example.
reply
This post is specifically about backend development, where you're not shipping software to regular users.
reply
This is just a matter of perspective. Backend IS being "shipped" to user via the API be it go or rust and inevitably the details and behavior do leak out to end user.
reply
Or it could be insane to pay the cloud memory costs when you have tools that can write rust for you.
reply
What "cloud memory costs"? Most Rust code is an informally-specified version of the old Python reference-counting GC. That's how you're supposed to write it, with clone() everywhere, and then dropping down to optimize. You can do the same thing with Go in the other direction by writing an allocator.

People believe a lot of weird things about these languages.

reply
Why would I roll custom allocation strategies in Go (and then be accountable for supporting them) that affect multiple teams and services when I can have an LLM port to Rust and get dozens of additional benefits?
reply
> and it's easy to make catastrophic mistakes

such as ... ?

reply
The use of LLMs has caused Rust usage to explode.

If youre not writing the code yourself and vibing away which I think most people generally are despite the disdain around here then why would you not choose the "more performant language" (I know that isnt necessarily reality but it is a common perception).

Go's managed runtime is less valuable when the LLM is perfectly happy to slap a bunch of stuff together for you to and approximate it and doesn't complain at all when writing async rust despite some of the rough edges.

reply
Correction: The use of LLMs has caused every major language usage to explode.

And as mentioned in other comments, Rust slow compilation can be detrimental to LLMs + fast iteration speed. And it's not just speed, Tauri takes 20GB of disk space to compile. It's bonkers. This is npm/js ecosystem all over again but slower.

Another reason to pick Go if you're leaning on LLMs is the standard library. Often you can do more work with fewer dependencies.

I'd rather leverage world class engineers paid by Google to maintain dependencies for me than try my luck with half a dozen of 0.x crates. Plus stdlib APIs can (and are) versioned just like third party dependencies.

reply
Fully agree with this. We use Rust in an enterprise setting for building web app backends and the experience is painful. A lot of crates just seem like someones side project. Too many ways to do things leads to bike shedding in PRs. Compile times are atrocious and can take like 30 mins to build.

Honestly using Go would have got us to the same point much quicker, with code that is much easier to review.

reply
I like vibe coding but I am sceptical that a vibe coded runtime in Rust would be as awesome as the Go runtime which is written with deep expertise of Unix software and threading and many low level details that are subtle and do depend on global properties of the code to work flawlessly. It makes sense you can crank out Rust with an LLM if you know what you are doing, but if you want a GC type thing or preemptive scheduling across an N by M threading model, then you are competing against some very good code.
reply
> the Go runtime which is written with deep expertise of Unix software

Go has no mmap(), import a 3rd party dependency for that and you'll get a segfault the very second you do a mistake.

Python has an mmap module which will catch many memory errors and present them as exception rather than causing a CVE.

reply
I don't agree with the parent comment, but mmap is exposed (low-level) in the standard library and there's a high-level wrapper in x/exp. You need to be careful with mmap no matter where you're using it.

What Go mmap CVE were you thinking of?

reply
> What Go mmap CVE were you thinking of?

Every time you see "segmentation fault", that right there is a CVE.

reply
No, obviously.
reply
I see the vibe security experts found my comment :D
reply
I agree that agents make Rust a lot more tenable for less "kernel-and-browser"-demanding tasks than it was 4 years ago, but I do not agree that they eliminate the "managed vs. unmanaged runtime" question, and to the extent they influence any of this decisionmaking at all, you have to accept the notion of not reading the code. If you're reading it, it matters that Rust makes you do bookkeeping that managed runtimes avoid.
reply
By that reasoning, we should all be vibing away C code. It's the most performant and efficient language out there, there's a ton of code out there the LLMs were trained on, and the complex logic of memory management is abstracted away by the LLM so you don't need to think about it.

Most people are not doing that though. There's probably a good reason, and it applies to other languages too.

reply
There is a good chance that your vibe coded C program segfaults immediately upon running and contains lots of subtle logic errors, all of which requires many iterations (finding issues at runtime) before you program runs as expected.

With Rust, you'll likely get many compilation errors, but if your syntax is correct, compilation errors will be few, and your code will almost certainly just work.

reply
I wouldn't build anything in C that I didn't absolutely have to, but, no, there is not in fact a good chance that your vibe-coded C program segfaults immediately.
reply
In order to use C you need to actually understand it, also toolchain is more complex etc. Which makes it a no go for 99%.

Rust is so safe that anyone can vibe it without any idea what is going on there. Which is basically what is happening here.

And why rust is more used than go for vibecoding? Mostly because of hype and performance gains which 99.9% of projects do not need.

reply
> performance gains which 99.9% of projects do not need.

most software isn't "needed"

reply
> The use of LLMs has caused Rust usage to explode.

Rust had a "vibey" community long before vibecoding. In particular, it's long been fairly non-serious about yolo importing a bunch of crates to solve things (since the standard lib is small) which is kinda the same problem as having all those things just vibecoded. Either way, most projects weren't reading all of that other code!

reply
deleted
reply
For the vast majority of software you want a managed runtime.

Some of the problems Rust “solves” are problems you shouldn’t be having in the first place because we mostly write software that doesn’t need direct control over memory. Borrow checking isn’t something you want to have to deal with - it is something you have to accept when you have chosen to manage memory. That choice has a high cost that cost never gets paid off in most projects that could work just as fine with managed memory.

I’m a Go programmer, but this article reminded me that I should have more experience with Rust. From my perspective Rust seems a bit less practical. The standard library lacks support for cryptography, for instance. The compiler is slow, which is a productivity killer. Overall concurrency seems like a bit of an afterthought. Again.

What makes me want to try Rust in production are things like option types. Those would be nice to have in any language. Any issues that can be caught by the compiler are a plus. Getting rid of nil would also be a plus, but to be quite frank, I don’t experience that many nil pointer errors.

The author does nod to the static analysis tools for Go. Yes, they are not part of the compiler (for good reason), but they do a pretty good job in practice. So you get more than the compiler can promise at a fraction of the cost (measured in build time). That’s a much bigger deal for actual developers than we generally give it credit for.

Then there’s the stuff that makes me less convinced in terms of arguments. For instance the fact that Go didn’t have generics early on and that the standard library doesn’t use them. Generics were not as important as people thought they were. In practical reality. The fact that the standard library doesn’t make wide use of them is not a weakness, it shows restraint. They didn’t go overboard and prematurely plaster generics all over the place as soon as the language supported it. This is the kind of restraint you want to see. Remember how horrible Java was after everyone started abusing generics? A brief generation of software that was significantly worse, and less maintainable resulted from this exuberance. For the ultimate example of what happens when you give people every feature they wish for: look at C++. It´s not a very good language because it is many languages. Just because there are standards and recommendations doesn’t mean that all code magically gets rewritten to a narrower definition of the language. It means that we accumulate intermediate forms. I expect people who are interested in languages to understand these dynamics.

reply
Rust's stdlib is small, Go took more of Python's "batteries included" strategy.

So in that sense it seems like a category error to try to look for crypto stuff in the standard library. Of course this brings the well known problem of "okay, but then which one should I use?". Nowadays this is largely solved by a few web searches and LLM queries, and people are quite helpful at https://old.reddit.com/r/rust/ .

Go was shaped by the needs of Google, Rust is a wildly successful amazing experiment in programming language and compiler design that really got out of hand :) (A bit like JavaScript! Or even C#! Or Python. Same growing pains (async/await!), but arguably on different levels.)

reply
Have you argued yourself to "it's a bad thing that the Go standard library has a cryptography library"?
reply
Us Node folks adapted typescript because we wanted static compiled types.

I wish TS had more of a runtime. The only thing I'm jealous of with regards to python is how seamlessly you can do JSON schema enforcement on HTTP endpoints. The Zod hoops are a constant source of irritation that only exists because the TS team is dogmatic.

reply
> The only thing I'm jealous of with regards to python is how seamlessly you can do JSON schema enforcement on HTTP endpoints.

Yes, it is much easier in Python because type annotations are reflected at runtime.

reply
I think Typescript is a perfectly cromulent language. I don't know it well but would seriously consider it for any problem that had a shape that admitted a dynamic language. There's a lot to be said for using dynamic languages, too!
reply
Every non-runtime language is dynamic after being compiled to x64 machine code!

It is illusions and lies all the way down the instant the compiler finishes its job.

reply
express-zod-api works well for me https://github.com/RobinTail/express-zod-api I'd say about as well as anything Python
reply
Check out Perry the TypeScript compiler to native code
reply
It sounds like you should try ocaml
reply
Indeed, if I were proposing contributions to the Linux kernel, or any other kind of systems development, I'd probably be considering Rust. For backend services, the decision is between C# and Go (with the latter being the favourite).
reply
I think I'd be ok with node via purescript? But in general I think rust and go people should join forces against the evils of dynamic typing. Isn't type hinting finally considered best practice now? I think that is effectively an admission that it was a defect. And even with good ginting it is still worse than inference. Inference can let plenty of code go untouched on type changes, while still protecting against unindended type changes.
reply
> Ultimately, if you have to ask, the Rust vs. Go consideration boils down almost completely to "do you want a managed runtime or not".

You don't need a garbage collector which is perhaps half of the Go Runtime when you're using Rust.

You can also bolt on a few crates and get ~95% of what you'd get from Go's runtime.

Go has the best runtime in the world. I'll give it that.

But this is not the only reason...

reply
You obviously don't need a GC when you're using Rust, because Rust doesn't plausibly have one.
reply
Right, so you don't need a large portion of Go's runtime benefits, because you have a far better version of it already, zero cost abstractions and TRUE memory safety, not pretend memory safety behind a -race detector with zero compiler guarantees...
reply
I don't know who you're speaking to, but it isn't me; I certainly didn't ask for the standard-issue Rust langwar pitch.
reply
> the Rust vs. Go consideration boils down almost completely to "do you want a managed runtime or not".

That's not really something I care much about. My beefs with Go are 90% about the syntax of the language itself, and it's weak (compared to Rust) type system.

When it comes to a managed runtime, for most tasks, I generally don't care if my language has one or not. For some tasks I do, but there are not many of those tasks, and so this question is mostly irrelevant to me when deciding Go vs. Rust.

I don't really get where you're seeing that the predominant Go vs. Rust debate is about the runtime. IME it's the subjective stuff about the languages themselves, and their ecosystems and communities.

> The Rust vs. Go slapfight is a weird and cringe backwater of our field.

::shrug:: I dunno, I mostly stay out of it and just use Rust, and I'm happy and avoid the drama. I've written a little Go here and there, didn't really like it, and moved on.

reply
That's totally fine. I don't get why people moralize this stuff. Both of these languages are rounding errors compared to the dynamic languages.
reply
I think people do this for every language. It becomes a part of their identity, and then they have to defend it. I used to do that too, long ago, but I don't have the time or energy for it for the most part, and find it boring, so that $LANG-user-as-identity bit of my has fallen by the wayside.

I don't think it's about adoption levels; sure Go and Rust are tiny compared to JS/python/etc. It's emotional, not about who has the most users or who can even plausibly get there.

reply
Because it triggers the "feeling of other" when someone is so close yet so far ideologically.

I'm sure you know this joke about dogmas :)

https://news.ycombinator.com/item?id=26624442

In some sense this is the same as the NIMBY/YIMBY question. There are perfectly valid reasons to want to live like Spacers do on Aurora, yet many prefer the caves.

reply
It feels like you’re upset because your favorite language has objective flaws that people are pointing out. You’re also trying to minimize people’s lived experiences and pleading with them to stop pointing the flaws out.

Sure, Go is better than Python in some things. But developers deserve the best. We deserve not to have to deal with Go’s quirks, idiosyncrasies and design mistakes.

reply
[flagged]
reply
Aren't you overlooking the main point of the article?, the reason they migrated:

> concurrency — eliminating data races essentially, which we had before. Really gnarly bugs

> this is the one teams report most enthusiastically. The classes of bugs that survive go test -race and reach production (data races, nil dereferences, missed error paths) just don’t compile in Rust. Oncall rotations are typically very boring after a Rust migration. ...

> I hadn’t had to chase down a crash, or some weird multi-threaded race condition, or some of these other things which actually consumed a huge amount of my time before.

(They say at InfluxDb)

That's not a Rust vs. Go slapfight? Instead, sounds like a good judgement to me

reply