Oh boy, this is going to be the new thing for Rust haters isn't it?
Yes, unwrapping an `Err` value causes a panic and that isn't surprising. Cloudflare had specific limits to prevent unbounded memory consumption, then a bad query returned a much larger dataset than expected which couldn't be allocated.
There are two conclusions: 1) If Cloudflare hadn't decided on a proper failure mode for this (i.e. a hardcoded fallback config), the end result would've been the same: a bunch of 500s, and 2) most programs wouldn't have behaved much differently in the case of a failed allocation.
.unwrap() is not required to be used.
use:
if let Some(value)=something_to_unwrap{
}else{ // log an error and exit!! }
1. Previous claims that Rust code often just works after compiling.
2. Previous claims that low-level error-handling idioms like matching, using Result, etc improve code reliability.
3. Previous claims that using unwrap in example code is ok for brevity. Also, Rust developers would know not to use it in production code.
4. The fact that significant portions of the internet were taken down because a production unwrap from a big, mature player and one of the Rust early adopters.
Sure, Rust is not the problem here, but rather Clownflare being too big and not having their SRE processes fully up to par for their size. Perhaps they are simply too big to operate at the needed level of reliability. However, Rust anti-fans can easily ignore the above and simply press the issue and debate the minutiae of error handling, human reliability, etc. It’s surprisingly effective and might even catch the ear of management.
However, this article is overall not at the level expected of Rust anti-fans in 2025. I commend the author for trying, but they need to improve in several areas like providing iron-clad real-world examples, proving the required level of experience, focusing more on pain points like dependencies and the potential for supply-chain attacks, addressing reskilling issues and internal corporate politics, etc. There was a blog by a veteran Rust game developer a while back which single-handedly destroyed the enthusiasm for Rust in gaming. That is the gold standard of Rust criticism for me.
2. They do. If you use them, which they didn't.
3. It is. Let's not discard personal responsibility.
4. The error would've happened in any language, Rust debatably made it easier to find though.
I don't write Rust code myself because I simply don't write any code that requires this kind of reliability, and thus I haven't expended the effort learn it properly. But if I were to start such a project, I would still go for Rust and learn it properly. I also don't have a "favorite" language. I just pick whichever seems most appropriate for the project, any decent programmer should be able to pick up any non-esoteric language to the point of adequacy in a few weeks anyway.
So why do they need Rust then? What advantages does it provide? That was the main point of the article — we all wanted a better language, but got another crappy one instead.
That Rust didn't prevent one error in one specific instance does not mean that Rust didn't prevent any errors across any instances. Nor does it mean that Cloudflare didn't benefit from Rust in some way(s) elsewhere.
For example, from one of Cloudflare's previous blogposts [0] (emphasis added):
> Oxy gives us a powerful combination of performance, safety, and flexibility. Built in Rust, it eliminates entire classes of bugs that plagued our Nginx/LuaJIT-based FL1, like memory safety issues and data races, while delivering C-level performance.
[0]: https://blog.cloudflare.com/20-percent-internet-upgrade/
No programming language should get flak for a bug that is not the fault of the programming language. This is Cloudflare's problem.
If you're going to criticize something, at least do it properly.
The move to Rust was partly motivated because it prevented that entire class of errors. No more out-of-bound reads, or data races. The compiler audits these missed spots.
Now, you could say a managed memory language would suffice as well. Perhaps it could. But we needed performance, and no memory-managed language met those performance needs then or today.
I get you're making the case that Rust isn't perfect for all use cases, but Cloudflare's scenario is the exact corner case your argument falls apart in: we needed fast and safe in an environment where not being fast or safe had real business consequences, and nothing else except Rust gave both.
So, is the Rust bad or good? It’s neither. It’s a mediocre programming language with thousands of man-month put into its development — this fact alone makes Rust a viable tool, just because you can pick it from the shelf and employ as-is. This blog was generated with Zola, written in Rust — I did not have to write a single line of Rust code to use it. And the Rust is a good fit for Zola SSG because of its non-interactive nature with one-way flow of immutable data. Just, please, don’t run around screaming “we should all switch our development to Rust because it’s the best programming language”.”
Is this what makes someone a Rust hater?
I disagree. There's a long road till that inflection point for me.
There was that article from the android team about how rust improved their development workflow[1]. Is that what you're talking about? Was that article emotionally upsetting? Do you wish it wasn't written? What in particular is upsetting? Do you want people to stop writing technical articles to protect your feelings?
Tl;DR Rust doesn't support any form of cyclic datastructure without indirection or unsafe. The indirection tooling is weak, and most real examples simply switch to unsafe rust. Unsafe rust is completely fine if you know what you are doing with memory, and is ok to use in these situations.
There are a few other gotchas that we just need to be clear about, some of these gotchas are limiting for developing higher level software and some are not e.g. String handling. If you are comfortable with unsafe, the rust toolchain is vastly superior to C/C++ development making it as close to an ideal replacement as we are likely to get.
In my opinion, unsafe rust code is worse to use than C because rust is missing the arrow operator. And rust still requires strict aliasing to be followed even in unsafe code. This makes complex unsafe code very hard to implement correctly. Like, it’s easy for something to look right and work correctly but for MIR to still find subtle issues.
Eventually I rewrote my btree on top of Vecs. My node & leaf pointers are now array indices. The result? There is no longer any unsafe code. The code has become significantly simpler and it now runs ~10% faster than it did before, which is shocking to me. I guess bounds checks are cheaper than memory fragmentation on modern computers.
I have so many thoughts having done that. First, I think this is actually the right way to write rust. Yes, manually keeping track of which array slots are in use is inconvenient. But unsafe & pointers are also quite inconvenient in rust. Programming like this makes use after free bugs possible to write. But it’s still memory safe by rust’s definition. It’s impossible to get arbitrary heap corruption because there are no raw pointers. And the indexes are bounds checked.
I also don’t think the resulting code is any worse than the equivalent C++. Everyone talks about memory safety but IMO rust’s best features are enums, traits, cargo, match expressions and so on. Even when you do a run around the borrow checker, it’s these features which make me keep coming back to rust.
I agree better guidance would be nice, but so many words have been spilled on rust already. Would you find content talking about subtle stuff like this? Sometimes the only way to learn is by trying stuff out.
In reality none of these things need the religious wars that seem to go back and forth. It's just an incredibly unfortunate and annoying aspect of how programmer-centric communities tend to go.
Somehow there are always fresh people who think someone cares or that somehow those are important discussions.
- Compile speed. Why do people care so much? Use debug for correctness and iterating your code. You're hardly going to change much between runs, and you'll get an incremental compile. Let rust-analyzer tell you if there are errors before you even try compiling. Let your CI do release optimization in its own time, who cares if CI is slow?
- The cloudflare bug was not caused by rust. Every language needs some way to say "hey this thing is invalid", and that's what happened when the list of AI tools got too long (or whatever their business issue was). Making the app panic was a design choice, not a language choice. Every language has a way to not handle errors.
- Things having unsafe {...} does not make them unreliable. On the contrary, if you run into a memory issue in a rust program, you know where to look for it. The problem in c++ was that the whole program was unsafe, and you then had no way to narrow it down. Memory safety errors are like type errors: a large class of errors that are worth checking for. If you're writing good c++, you have a linter that checks similar things anyway, and if you're disciplined, you've also upgraded warnings to errors. FWIW, I do think the marketing over-emphasizes memory management, because there are a lot of these hard learned lessons that are default in rust but optional in c++.
- Mutable shared state: make bad designs hard to write. Mutable shared state is another one of these eternal bug sources. Use channels and pass messages.
Honestly, it reads like a lot of critiques of Rust: people haven't spent enough time with it, and are not over the learning curve yet. Of course everything is cumbersome before you're used to it.
Yeah. Rust’s Option::None as like null in C++. Unwrapping an option is like checking if something is null and crashing. This "crash from an unwrap" is just a null pointer exception / segfault in any other language. The same bug would be trivial to write in any other language, and with more or less the exact same result. Its just - weirdly news because it was rust code. What?
> Honestly, it reads like a lot of critiques of Rust: people haven't spent enough time with it, and are not over the learning curve yet.
Exactly. I’ve spent years with rust and my complaints are very different. Well, I still wish it compiled faster but all the other stuff is noobie problems. As someone with more experience, my frustration points are things like how async blocks do compiler magic you can’t write yourself. I hate unnameable types. I think Pin is confusing and weird. And the syntax for interacting with raw pointers is unnecessarily inconvenient and ugly.
Yes, rust makes programs with a lot of shared mutable state awkward to write. So don’t program like that. In general, if you write code in language X as if it were a bad version of language Y, you're going to have a bad time. The right question here is if the "rust way" of thinking about your code results in a beautiful program. You can't answer that if you go in with too many preconceptions of how programs should be designed.
I say this as a Rust advocate and daily Rust programmer, btw.
Both Option and Result can be unwrapped and - to some extent not coincidentally - both can also be subject to the Try operator (?) which is arguably more correct here than unwrap because this can fail and perhaps the caller will have some plan to recover.
My list of peeves would be very different from yours. I would like to prohibit move of the dodgier as casts (requiring that you write out the conversion call you actually meant explicitly and then handling any edge cases) for example.
What sort of "interacting with raw pointers" are you thinking of that's too inconvenient and ugly for your liking?
Ardour is a real-world, mid-size project. About 1.3M lines of code, almost all of it C++. On the fastest typical x86_64 systems, it builds in about 1.5mins, on an M3 it builds in about 3.5mins, on a somewhat older x86_64 16 core system it builds in about 7.5mins.
If you ever touch libs/ardour/ardour/session.h or libs/pbd/pbd/stateful.h, you're in for an almost complete recompile. If you touch libs/temporal/temporal/timeline.h, same thing. That's just the day to day work of being a developer of a native desktop application - nothing to do with CI or releases.
That's why some of us care.
Also makes good designs hard to write, designs that can be significantly more efficient.
Passing messages is not a universal solution to shared mutable state. It is great for certain patterns but suboptimal for others.
For example you can just write a lockless triple buffer for efficient memory sharing and wrap the unsafe usage of pointers with a safe API. now you only need to pay attention to those specific unsafe calls.
Even if you know you're code compiles, it's often easier and faster to validate the logic or complex interactions by running the code. In large (and even not so large actually) projects, debug builds can be painfully slow, even on good hardware. It's important to have a tight feedback loop so that you can interate quickly.
What's the largest Rust-based public codebase so far? Rustc with like 1 million lines of code including all the dependencies in all the languages? Zed IDE has 800k lines. Incremental compilation seems to work fine at this scale, but things become messy above it. Most people prefer to not exceed the limit.
>Mutable shared state: make bad designs hard to write. Mutable shared state is another one of these eternal bug sources. Use channels and pass messages.
People think BEAM (Erlang/Elixir) does not have shared mutable state because the programming model says so, but it actually has some mutable shared state transparently under the hood i.e. implementation details and runtime. BEAM processes all run in a single OS address space, they are not even separate threads but async tasks spread out across OS threads — and still per programming model of the language those are "shared nothing". So in the end BEAM is a very good abstraction on the partially shared mutable state.
And no, in BEAM remote messaging is not nearly the same as local messaging. For example, you don't have built-in supervision trees on remote, and ETS is also local-node-only.
I do agree that hardware model of shared mutable state is inherently problematic, but we don't have other commodity CPU-s yet — you have to handle the shared mutable if you wanna be close to hardware.
>It reads like a lot of critiques of Rust: people haven't spent enough time with it, and are not over the learning curve yet. Of course everything is cumbersome before you're used to it.
Well, at least you confirm that the complexity is real. Don't get my criticism to close to the heart though — I did exaggerated the problems a bit, because someone needs to counteract the fanboys.
This isn't true, no matter how much people keep saying it. Unsafe does not scope bugs to the block, or even where you have to look for bugs. Just having unsafe in your codebase means changing code outside the unsafe block could cause UB.
Doesn't mean I think it's worth complaining about, there's really no better way for Rust to do this without sandboxing memory.
Not a fact. Particularly in the embedded world, crashing is preferable to malfunctioning, as many embedded devices control things that might hurt people, directly or indirectly.
> If a pacemaker stops — telling a victim “but the memory was not corrupted in the crash” is a weak consolation.
If a pacemaker suddenly starts firing at 200Hz, telling a victim "but at least it didn't crash" is a weak consolation. A stopping pacemaker is almost always preferable to a malfunctioning one, as most people with pacemakers still have sufficient natural rhythm to survive this for long enough to get help.
> We actually had a recent Cloudflare outage caused by a crash on unwrap() function
Please read the whole article. If the unwrap hadn't caused an exit, the process would've run out of memory, leading to a much less deterministic behavior which is much harder to diagnose and fix. I always prefer an early exit with a clear error instead of getting killed by the OOM reaper.
Like, if the rule were "Always-Keep-Running" then hospital equipment power supplies wouldn't have circuit breakers that cut the power when something is wrong. But cutting power seems lot easier to detect for the backup power supply so it can fully take over.
“It crashed on an assert…”
Pointy haired boss:
“… well, what are you waiting for!? remove all the asserts so it doesn’t crash any more!”
I love to write in Rust precisely because I can express failures more explicitly, it’s the transparency that wins here.
I’d frame the issue Cloudflare had rather in the PR review and QA corner, maybe as some AI complacency. But it’s not a problem with Rust.
Motivated reasoning
It was trying to push an element into a full ArrayVec. The options are:
- Blindly write off the end of the array. Obviously no one wants this, despite the decades of tradition...
- Panic and unwind, as the program actually did in this case.
- Return an error.
Some folks assume that returning an error instead of unwinding would've been better. But my assumption is that the outcome would've been the same. I think the issue came up when loading configs, which isn't usually a recoverable situation. If you have an "invalid config error", you're probably just going to return that all the way up, which is effectively the same outcome as unwinding: your process exits with an error code. There are cases where the difference matters a lot, but I don't think this was one of them.
The real gap seems to be why it took hours for folks to notice that this service was crash looping. That should normally be really prominent in alerts and dashboards. (Probably part of the story is that alerts were firing all over the place. Tough day at the office.)
It really depends on how deeply Turing you mechanism is. By being "Turing" I mean "the behavior is totally dependant on every single bit of previous information". For a reliable system turing-completeness is unacceptable for separate functions i.e. it should produce a correct result in a finite amount of time no matter what hapened in the past. Particulary, that's why modern real-time systems cannot be fit into Turing machine, because Turing machine has no interrupts.
>If a pacemaker suddenly starts firing at 200Hz, telling a victim "but at least it didn't crash" is a weak consolation. A stopping pacemaker is almost always preferable to a malfunctioning one
You almost make an excuse for general unreliability of programs. Mainstream C is unreliable, C++ is unreliable, Rust is unreliable. I can agree that Rust is not less reliable than C/C++, but it is definitely less reliable than some other language e.g. BEAM-based ones. I mean in Rust standard library some time ago I actually read "in these and these conditions the following code will deadlock. But deadlock is not an undefined behavior, so it's ok". The designers of Rust did not really try to support any kind of "recover and continue" way of functioning. Yes, you can catch the panic, but it will irreversibly poison some data.
Strong agree on this one, usually embedded systems are designed to "fail safe" on crash - the watchdog will trip, and hardware reset will put everything in a deterministic, known safe state.
What you want, above all else, is not to fall into undefined behavior. That's the beauty of `unsafe`, it bounds UB into small boxes you know to test the hell out of.
A pacemaker in an unknown state goes forever undiagnosed.
>Please read the whole article. If the unwrap hadn't caused an exit, the process would've run out of memory, leading to a much less deterministic behavior which is much harder to diagnose and fix. I always prefer an early exit with a clear error instead of getting killed by the OOM reaper.
I am running into an undiagnosable CUDA "illegal memory access" problem in vLLM, a code base that is a mix of python and CUDA (via pytorch). At a certain load something appears to either overflow or corrupt the memory and vLLM restarts, which takes a minute, because it has to reload several dozens of GBs into memory and then rerun the CUDA graph optimizations.
The pacemaker argument is complete nonsense, because the pacemaker must keep working even if it crashes. You can forcibly induce crashes into the pacemaker during testing and engineer it to restart fast enough that it hits its timing deadline anyway. Meanwhile a silent memory corruption could cause the pacemaker to enter an unknown state where the code that runs the pacemaker algorithm is overwritten and it simply stops working altogether. Having a known failure state is a thousand times more preferrable to an unknown number of unknown failure states. Critical sections (mutexes) and unsafe code has to be panic free (or at least panic safe) in Rust, so the concept of writing code without panics isn't exactly a niche concept in Rust. For every panic based feature, there is usually a panic free equivalent.
I'm actually the one who promotes paranoidal assert-s everywhere. I do agree the original statement from the article is ambiguous, probably should have written something like "memory safety in Rust does not increase reliability".
>The pacemaker argument is complete nonsense, because the pacemaker must keep working even if it crashes. You can forcibly induce crashes into the pacemaker during testing and engineer it to restart fast enough that it hits its timing deadline anyway.
I'm not sure whether there is a deadlock-free modification of Rust — deadlock is not considered an undefined behavior in Rust.
I argued that requiring expect("expectation") calls rather than unwrap() instils the discipline to consider what you're expecting and thus why you think we won't panic - to write the text in the expect call, but I did not convince them and they remained sure that what Cloudflare needs is better deployment discipline not improved engineering practices.
† It is a coincidence that they work for Cloudflare, it was quite intentional that I spent much of my weekend with them, we were playing video games.
Do note that C did not have such a flaw built into language — C++ authors invented it and Rust inherited this flaw (the authors simply did not feel like it's a flaw). I mean specially designed embedded C code can survive total RAM erasure and still perform some meaningful work (with CPU registers and ROM intact). Or compare it to BEAM that can have processes crash all day long and still continue to work. "Memory safety at all cost" is not a practical requirement — it's theological.
catch_unwind exists for a reason.
> e.g. when you have an exception in a destructor then it's a guaranteed `std::terminate`.
You can throw in a destructor [1]. You just need to mark that destructor noexcept(false). You do get a guaranteed std::terminate if an exception escapes a destructor while unwinding is already underway, though.
> Do note that C did not have such a flaw built into language
assert() says hi?
> I mean specially designed embedded C code can survive total RAM erasure and still perform some meaningful work (with CPU registers and ROM intact).
Why doesn't a similar argument apply to "specially designed" Rust?
> Or compare it to BEAM that can have processes crash all day long and still continue to work.
Again, nothing stops you from writing Rust that does the same.
[0]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
let a = b.unwrap();
is conceptually no different to: if (b == NULL) {
abort();
}
a = *b;
don't write either if you don't want to halt.Recoverable error mechanism in Rust: https://doc.rust-lang.org/std/result/enum.Result.html
> Its compilation is slow. I mean SLOW. Slower than C++.
No way. Maybe Rust 1.0, but it's steadily improved and it's definitely faster than C++ now.
> It’s complex. Just as complex as C++.
True, but the problem with C++'s complexity is that you have to memorise all of it or you'll accidentally invoke UB. It's so complex that is basically impossible.
Rust is complex but most of the time the compiler will tell you if you got it wrong. There are exceptions of course (lots of async footguns) but it's still night and day.
> Memory safety is not that sacred. In fact, for many applications malfunctioning is better than crashing
Not sure I really need to counter this...
> When handling lots of mutable shared state (GUI, DB, stateful services, OS/hardware), the performance of native Rust memory model is subpar, and non-native unsafes just leave you with slow compilation, high complexity, and no memory safety in the end — which makes Rust practically meaningless for heavy mutable state jobs.
Not totally clear what he's getting at here. Maybe the ergonomics of GUI style programming which are still being figured out? Hardly a deal breaker though is it? There are plenty of C/C++ GUI libraries with terrible ergonomics and the only one that is actually great (Qt) had to use a custom language extension for decades to achieve that.
> So, is the Rust bad or good? It’s neither. It’s a mediocre programming language with thousands of man-month put into its development
I would love to hear what he thinks a good programming language is, because I can easily pick more holes in any other language than he has.
This anti-Rust zealotry is super tedious.
Language wars are boring and pointless, they all have areas of suckage. The right approach is to pick whichever one is the least worst for the job at hand.
not OP, but outside of extreme performance critical software I MUCH prefer Swift, C# or python.
Also, not the OP, but I bet it is Python.
- No compile time.
- Not as complex as C++.
- Memory Safety, while they don't care about this apparently, but nice to have.
- Plenty of ergonomic GUI style programming, like PySide (Qt for python).
Of course, I know there are many downsides to python. Such as interpreted languages, especially ones that are duck typed are very slow to run... but that's not one of the OP's complaints.
Unfortunately I don't think their critique is really coherent—this is an absurd standard.
I have a working theory that the classic programming is basically dying out: https://bykozy.me/blog/llm-s-are-not-smart-rather-programmin... You just cannot write fast and reliable program neither with C++ nor with Rust, because the fundamental model is broken and nobody's really bothered fixing it.
D language smiling in the corner [1].
"D supports Ownership and Borrowing, just like Rust. DMD, D's reference compiler, can compile itself in less than 5 seconds, thanks to a fast frontend and fast backend. D is easy to metaprogram through traits and templates. You can make your own JIT in D with dynamicCompile." [2]
[1] Kevin James meme creator tries to guess why the photo went so viral:
https://www.yahoo.com/lifestyle/kevin-james-became-internets...
[2] Ask HN: Why do you use Rust, when D is available?
There are appropriate ways to contrast D with Rust and illustrate where D is stronger, but it is inaccurate to say "Rust has borrowing; D has borrowing" and conclude that they are comparable in this sense.
Indeed, there are languages that have generics, compile blazingly fast, and still have good runtime performance. Go lang is another good example, although not perfect too. If only Rust designers did a single thing to make it compile fast instead of "eventually".
> Memory safety is not that sacred. In fact, for many applications malfunctioning is better than crashing — particulary in the embedded world where Rust wants to be present. You cannot get 99.999% reliability with Rust — it crashes all the time.
Yeah until that memory safety issue causes memory corruption in a completely different area of code and suddenly you're wasting time debugging difficult-to-diagnose crashes once they do start to surface.
> We actually had a recent Cloudflare outage caused by a crash on unwrap() function: https://blog.cloudflare.com/18-november-2025-outage/
There were multiple failures before that `unwrap()` and the argument can easily be made that this is no different than an unchecked exception or a release assertion.
> Sync/Send, Mutex and reference counting (Arc)? Unfortuantely, those lock or simply mess with CPU caches badly, so they are inefficient for multithreaded communication, at least an intensive one. They are safe, but inefficient. Which kinda destroys the first uncompromising thing in Rust — performance.
Doing this the "correct" way in other languages has similar impact? So I'm not sure why Rust forcing you to do the correct thing which causes perf issues is uniquely a Rust issue. Doing this the "just get it done" way in other languages will likely come back to bite you eventually even if it does unblock you temporarily.
There are plenty of times I did a `static mut` global in Rust just to get some shit done and oops, accidentally hit some UB as the project grew.
Some very solid argument here. However, as already implied in my article, you can get most of the guarantees without losing your sanity. Memory-safety-related problems are important, but they are not the sole source of bugs in applications — as developers of Zed found out.
>Doing this the "correct" way in other languages has similar impact? So I'm not sure why Rust forcing you to do the correct thing which causes perf issues is uniquely a Rust issue. Doing this the "just get it done" way in other languages will likely come back to bite you eventually even if it does unblock you temporarily.
It might be counterintuitive, but garbage collectors in multithreaded code can be very efficient. I mean you just spawn lots of objects with random references in between and then eventually GC untangles the mess — it's zero overhead until the GC cycle. Escape analysis and semantic-reach containers can reduce GC work a lot (so you don't have the classical JVM GC problems). More specialized things like RCU and general quescence-state reclamation can be totally pause-less.
I think this is part of why your article is causing a strong reaction from a lot of people; quite a lot of the justification for your point of view is left implied, and the concrete examples you do give about Rust (e.g. `Arc<Mutex<Box<T>>>>` and `.unwrap`) are hard not to see as straw men when plenty of people write Rust all the time without needing to rely on those; it turns out it's also possible to get more reliability out of Rust for those people without losing their sanity.
Most of the opinions you give are hard to distinguish from you personally not finding Rust to provide a great experience, which is totally valid, but not really indicative of "core problems" in the language. If you instead were making the argument of why you don't personally want to write any code in Rust, I don't think I'd have much criticism for your point of view (even though I wouldn't find much of it to apply to me). Then again, the article starts off with a statement of previously having made an intentionally provocative statement purely to try to compensate for a perceived bias in others, so maybe I'm just falling for the same bit by trying to engage the article as if it's serious.
Yeah sure, but what compares that gives you similar perf, safety, and language features to Rust? I'll use "safety" in a loose term to say "you really infrequently encounter odd memory safety issues". Go for example still has the occasional memory corruption issues with maps in particular although these don't show up too often and the race detector exists.
C# is probably the closest I can think of for AOT? I don't really know what the deployment story for a .NET application looks like these days though.
Go has some language design things that turn people off.
>but they are not the sole source of bugs in applications — as developers of Zed found out.
You called out Zed in the blog post as well but I've not seen the Zed devs expressing regret of using Rust. Is this just an assumption on your part? As someone who's written many UI applications with egui and one with GPUI, I've felt some minor pain points but nothing show-stopping.
I used to write a lot of C#. I used to write a lot of Go. I now write either and basically exclusively write Rust these days and a bit of C/C++ at work. The only time I've really felt the pain of `Rc<RefCell<...>>` gross types was recently when trying to port a game engine's data loader to Rust. It makes heavy use of OOP patterns and trying to emulate that in Rust is asking for a bad time, but I did it out of just out of trying to one-shot the migration and keep logic similar. Not fun, but I knew what I was getting myself into.
What has garbage collector to do with multithreaded code? Once you have two or more threads which needs to share data, they need to sync and you'd end up using some kind of lock, which will affect the performance. GC doesn't make anything efficient or less efficient here. It might make the code simpler as you don't have to worry about allocation/deallocation, but I don't see how it's magically going to remove the lock.
It is indeed. But on the flip side, no other programming language is going to give you a compile error if you forgot to wrap you data into a mutex before sharing it between threads, and you'll either end up with a ConcurrentModificationException exception at runtime (Java) or with an undefined behavior.
But otherwise yes, there are plenty of situations where a GC is a totally valid solution. Just not for most of Rust's niche.
Yes you can have other bugs. What is this argument about? How about having just other bugs instead of other bugs and memory unsafe bugs?
For my reality of developing for smaller projects than Android, I will absolutely weight Android team's opinion less than the opinion of smaller projects.
Trying to mimic FAANG engineering practices is a fools endeavour that ranges between naiveness at best and CV padding at worst.
This is incorrect in a way that honestly feels insulting. It's not the language's fault that you called the `crash()` function—every language has a way to terminate execution, and for good reason. Crashing isn't even necessarily incorrect behaviour; that's how you pass the error up to the infrastructure layer for handling. The problem here existed at a system design level, not a language level.
For the author to paraphrase this (bad) critique like this:
> You cannot get 99.999% reliability with Rust — it crashes all the time.
is outright dishonest and insulting to me as a reader.
Because unwrap() is not guaranteed to cause a crash? panic!() is there if you actually want to guarantee a panic.
Second, you totally missed the OP's point about reliability. If one has to choose between UB and an immediate halt, those are pretty sucky options. And the OP is 100% right about Rust crashing all the time. Nothing insulting about that, just a fact.
It’s not a reliability issue of the language if as an author of software you choose to crash in your failure handling cases. Claiming otherwise is either disingenuous or a failure to understand what actually happened.
It's true that it's easier to write correct async code using immutable shared data or unshared data.
However, it's very hard if not impossible to do fast and low memory concurrent algorithms without mutable shared state.
This explains why massively parallel HPC codes are mostly minimal mutable state designs despite seemingly poor theoretical properties for parallelism. Real world performance and scalability is dictated by minimization of memory copies and maximization of cache disjointness.
But it's really an 'it depends' situation.
The fastest algorithms will smartly divide up the shared data being operated on in a way that avoids contention. For example, if working on a matrix, then dividing that matrix into tiles that are concurrently processed.
Memory safety and thread safety are causes of heisenbugs. However there are other causes. Rust don't catch all heisenbug. But not being perfect doesn't mean it's useless (perfect solution fallacy).
The article has some valid points but is full of ragebait exaggeration.
Given that Rust doesn’t always have critiques that are backed with evidence, this wasn’t bad.
People can use C now that LLMs make it easier, so Rust is no longer needed in many ways.
What evidence?
Personally my biggest complain from Rust is that I wish it was more readable. I've seen function signatures that seemed straight out of C++.
There is always a trade-off. You really cannot provide enough information for the compiler without the current signatures. There is a certain point where you cannot compress the information without losing some features.
You make the signature shorter but also take away the ability for the programmer to quickly understand what code is doing.
It's still quite rough around the edges, but Crystal is a fun choice for this type of thing. If you want a readable high level language and sane package manager that compiles to reasonably performant machine code, it's worth a look.
Zig... is surprisngly used a lot given how rough the state of the language is. It makes me think that if it ever reaches v1.0, it has a very good chance of being at least a "Kotlin", probably a "elixir"/"haskell", and a decent enough shot of "typescript".
Node JS has had vulnerabilities in the past: https://www.cvedetails.com/cve/CVE-2021-22940/
Go is also not Memory safe: https://www.ralfj.de/blog/2025/07/24/memory-safety.html
There are essentially just two mainstream memory-unsafe languages: C and C++.
This is not the language problem, but its simply the nature of the problem no? It is like saying, full adders are complex, can't we design something simpler? No, full adders are the way they are because addition in binary is complicated.
What you are saying is that this problem is not your kind of problem, which is fine. Not everyone needs to face the complexity of optimizing full adders. And so we created abstractions. The question is, how good is that abstraction?
C++ is like using FP math to do binary addition.
I say that as someone that thinks Rust's learning curve is the main reason it rarely makes economic sense to use it.
On the one hand, I don't regard it as a real "problem" because as the post says, it's by design and the design is that you pay the compilation cost but in return you get something valuable from it: fast safe code. So you pay a fixed cost to compile during development and it's your users and future you who get the benefit of future performance and stability. This is why Rust users are usually okay with it, because the more you use Rust, the less you pay for the compile times.
On the other hand, I'm sitting here now 20 minutes into building a random Rust project I found (I believe it's AI vibecoded so I won't link it). It's only 3000 lines of Rust code... I honestly cannot fathom why it's taking so long, because I have a codebase of 100kloc Rust with more dependencies and lots of macros, and that takes only about 2 minutes to compile from scratch. But apparently, some people/machines can write Rust so bad that 3000 lines takes 20+ minutes, and that's just not good at all for Rust.
So whereas the slow compilation times are by design, I think perhaps if my daily experience were 3kloc taking 20 minutes to compile, I wouldn't ever use Rust. So I'm wondering if that's how some people's experience with it goes, leading to the disparity of opinions. I kind of want to figure out why this particular project is taking so long to avoid whatever trap the AI coded itself into
(aside: this is another problem with AI that I hadn't thought about yet... a human programmer would have noticed the rapidly ballooning compile times and corrected for them before they got absurd; whereas the AI writes it all at once and doesn't factor how the code impacts compile times. So it maybe be technically correct, but also pathological).
This does seem like a poor design decision by Rust to me, forcing people to break things into arbitrary crates just to get reasonable compile times.
It also seems like a disaster for incremental compilation.
Not necessarily, since codegen units can introduce intra-crate parallelism during compilation.
But in any case, as with basically everything there are tradeoffs involved in choosing compilation unit size. Making your compilation unit crate-sized also means that you have some more flexibility in your code organization (e.g., stuff can mutually depend on each other, which is itself potentially useful and/or harmful) and you don't run into other potential issues like the orphan rule. There are also potential impacts on optimization, though LTO muddy the picture. Codegen units are just the cherry on top.
There's almost certainly other things I'm forgetting and/or not knowledgeable about as well.
Grrr. Clueless people keep saying that. People have been verifying programs for over forty years now. Formal correctness in terms of not violating assertions is possible for most useful programs. As someone pointed out about the Microsoft Static Driver Verifier, if you're program is anywhere near undecidability, it has no business being in the kernel. This not a legit criticism.
who the hell cares just about "the kernel" (whatever kernel that is) ? I write native desktop applications and they are completely unverifiable.
A quick search of HN shows a bunch of articles, "X is a disappointment," which aren't flagged. Do folks have such thin skin about this topic that expressing disappointment deserves flags?
Refactor your build.
>It’s complex. Just as complex as C++. But C++ had legacy and Rust had not. The complexity of forcing your way through the jungle of Arc<Mutex<Box<T>>> on every single step directly impacts the quality of the logic being implemented i.e. you can’t see the forest for the trees. Once again, C++ has the same problem, so what’s the point of the language switch in the end?
If you can come up with something better, write a macro for it.
>Memory safety is not that sacred. In fact, for many applications malfunctioning is better than crashing — particulary in the embedded world where Rust wants to be present. You cannot get 99.999% reliability with Rust — it crashes all the time.
Learn the language a bit better, use code coverage tools, and write better tests.
>When handling lots of mutable shared state (GUI, DB, stateful services, OS/hardware), the performance of native Rust memory model is subpar, and non-native unsafes just leave you with slow compilation, high complexity, and no memory safety in the end — which makes Rust practically meaningless for heavy mutable state jobs.
True for C++, too, if you don't implement things properly.
People do this, and at best it works for some people. This kind of messaging towards people who bring up a valid criticism of Rust does not help.
Zig and Odin are much more enjoyable to write and provide enough safety for a lot of applications, and Go gets you 90% of the performance of Rust without the complexity.
If you need that, you go Ada.
Rust is practically the same as Zig, when compared to Ada.
But yes, this sure is a nice and sane thread.
How is `T` broken? How are the other things broken?
No matter what language you use, most of the code running between what you wrote and the hardware will be written in C. Your choice for the 1% on top is not very consequential. There is still a huge attack surface area no matter what.
The goal of changing that is a big part of why there’s so much discussion about Rust.
> Your choice for the 1% on top is not very consequential. There is still a huge attack surface area no matter what.
For an internet-exposed service, the 1% that implements that service is important. Most of the rest of that attack surface is only accessible if an attacker gets past that first layer.
That is, building applications out of premade parts is a struggle in C or C++ or rust because memory management is part of the API. C devs would be very concerned about having control of memory allocation and would like to have the choice of reusing a buffer from the application in the library or have the library allocate into an arena managed by the application, etc. It’s complicated enough that libraries can’t reasonably support every scenario application developers would like and ultimately tough because to free something the application has to know if the library is done with it or the library has to know if the application is done with it…. However, the garbage collector knows!. In the end there are a lot of libraries you can’t really write for C or if you can write them you have to write them assuming the application allocates or a certain way or you lose the benefit of being in control of allocation that C allegedly gives you.
On the flip side I think C is too high level in some cases, for instance you come to think the gymnastics involved in written embedded C or device drivers are normal but there are quite a few things that are a little bit cleaner in assembly language and I write things for AVR-8 that are rather small but it drives me nuts that C is moving the stack pointer around and following calling conventions that are not at all necessary for these particular programs.
I had friends who worked in the IBM Mainframe world where it is still common for applications to have bits written in assembly because of efficiency or to get finer control than you can get with COBOL. Part of the COBOL puzzle is that you have to be a Macro Assembler programmer to work on that stuff and you can’t just port it to GNU COBOL on Linux without also porting the assembly!
We’re still living in a multi-architecture world so the interesting idea of trying to make it easier to write assembly (imagine a super macro assembler with an integrated theorem prover) is a non-starter. Let x86 founder for a decade and if RISC-V makes no progress that picture could be different in a few years.
The author dismisses these defects, but try telling a financial institution that it's "only" corrupt user data when the books don't balance. Explain to an aerospace company that acting sporadically is just fine.
Then I discovered that C++ has a very cool feature that Rust doesn't have: jobs.
Now, I no longer search for Rust positions.
Yeah, just another data leak, no biggie.
One thing that this blog doesn’t address though, is the cult-like following of Rust. It’s like the “AI” of oss — a main selling point by itself despite not being a feature. Seemingly, there is an assumption that software written in Rust is inherently better than any other, or that if something is written in Rust, it cannot have any errors.
Sure, new software should be written in it instead of C. But why fix programs that are already memory safe?
Yes. Both Rust and its standard library have features that make programs be less likely to have problems.
> than any other
No. It's just better than the languages that are very popular right now.
> or that if something is written in Rust, it cannot have any errors.
No. How people keep jumping from "better" to "absolutely 100% infallible" is beyond me. Nobody is claiming this.
> But why fix programs that are already memory safe?
Because:
1. Programs that are already memory safe still need to be improved, and those improvements are really dangerous in a dangerous language
2. Things like https://news.ycombinator.com/item?id=46013579
Without trying to evaluate a claim about which is more "complex", since that's somewhat subjective (even if I do have some feelings on the matter), I can pretty definitively state that the vast majority of the concurrent code I've written in Rust has not used Arc<Mutex<T>> at every single step (and I don't think I've _ever_ used `Arc<Mutex<Box<T>>`, which would be like having `std::shared_ptr<std::mutex<std::unique_ptr<T>>>` in C++). It's totally valid to argue that the learning curve for Rust is sharp, but I don't think they've made a great case for it here generally rather than just for their specific experience. This even further implied by the idea of a "language switch"; I've been programming Rust for a decade, and I only learned C++ after learning Rust, so from my perspective, I'd have to "switch" to C++ from Rust, and it seems similarly pointless to do so. (I understand my experience is probably atypical, but that's kind of my point; everyone's perspective is different, and I don't think that making an argument based almost entirely out of subjective personal experience speaks very well to a "core problem" in a language unless you can speak to why that's representative of the general experience most people have, and I don't think they've done that here at all).
This is not objective. You're entitled to your opinion, but I at least am fine with compile times the way they are. For it to be objective, it would have to be something that is true independent of your or my opinion, but ultimately this is a subjective matter.
> Memory safety is not that sacred. In fact, for many applications malfunctioning is better than crashing — particulary in the embedded world where Rust wants to be present. You cannot get 99.999% reliability with Rust — it crashes all the time.
This is a completely baseless assertion; Rust does not "crash all the time". If a programmer chooses to crash rather than keep going when the program is in an unforseen state, that is his choice, not something the language requires. Presumably that programmer feels that crashing is beneficial (because it helps to make bugs obvious sooner), but you aren't required to do the same.
I am more concerned about correctness and "zero-cost abstraction" of the end result, if sacrificing few seconds of compilation time is necessary for that - fine by me.
> It’s complex. Just as complex as C++. But C++ had legacy and Rust had not. The complexity of forcing your way through the jungle of Arc<Mutex<Box<T>>> on every single step directly impacts the quality of the logic being implemented i.e. you can’t see the forest for the trees. Once again, C++ has the same problem, so what’s the point of the language switch in the end?
So, you seem to prefer data races and dangling pointers, or? Have you tried "actors-like" channels+rayon approach if you hate mutex so much?
> Memory safety is not that sacred. In fact, for many applications malfunctioning is better than crashing — particulary in the embedded world where Rust wants to be present. You cannot get 99.999% reliability with Rust — it crashes all the time.
You again prefer UB and/or corrupted state (and call that "reliability") over required explicit checks of Result via matching. This is definition of bad code to me.
> When handling lots of mutable shared state (GUI, DB, stateful services, OS/hardware), the performance of native Rust memory model is subpar
Few boundary checks sometimes add negligible overhead, but again you need those in any language to enforce correctness, Rust just adds those automatically.
> Memory safety is not that sacred. In fact, for many applications malfunctioning is better than crashing — particulary in the embedded world where Rust wants to be present. You cannot get 99.999% reliability with Rust — it crashes all the time.
Would you prefer silent UB/memory corruption in Cloudflare case? I don't think most developers would agree with this.
> Its compilation is slow.
I agree on this. But you can get better hardware, split a large code base into several crates, optimize for fast compilation when developing. On the other hand, I feel the guarantees of Rust compilation are discounted. If your code is more correct before deployment, wouldn't that save you debugging time later?
My biggest issue is with macros. I like them (and LLMs are good at writing macros) but they make both compilation and LSP ridiculously slow.
> It’s complex.
No, it is not. There is a learning curve. But after a while, you just alias your "Arc<Mutex<Box<T>>>" and name it something you understand (mypipedtype) and then just fly over the abstractions. There is sunk time to build/architecture your complex type but I see that as investment that can save you time later.
> In fact, for many applications malfunctioning is better than crashing
What does malfunctioning mean? Leaking your secrets? Compromising your system? Corrupting your data/state? I'd take crashing any time of the day.
> When handling lots of mutable shared state (GUI, DB, stateful services, OS/hardware)
This is a problem until the whole stack becomes Rust. If you are using lots of extern/FFIs in your code, I really sympathize with your position and you are kind of in a worst of both worlds situation.
Uptime isn't reliability; it's producing predictable behavior. Allowing indeterminate ("malfunctioning") behavior is the opposite of reliability.
doing that first when setting up an rpi is a good way to not only grab a bunch of useful programs like exa and bat, but it also functions as a nice benchmarking and stress test tool. i can check my heatsinks and fans, and grab a smoke and a coffee, while cargo compiles an app that concatenates a file with syntax rendering
> People create lies to gain power and money. Which is kinda what I was supposed to do, but for random reasons I went rogue and chose sanity instead.
> I am anti-bullshit.
These "contrarian for the sake of being contrarian" vibes naturally flow into this Rust post. Rust has a ton of faults, but this is was a very shallow critique.
Yes C++ has many many issues, and yet most of the biggest most complex software systems in existence are written in it. I don't see the browsers, OSs, DAWs, AAA games etc. being implemented in Go. Rust is a real improvement for these areas, with a proven track record of making software more reliable and maintainable.
If the author intended to say "Rust is not the best programming language for every problem" they should have said that but it would have been worth an article as much as "Screwdrivers are not the best hammers".
Rust attempts to solve this trifecta and that is where the complexity arises. If the problem at hand does not need async, then Rust has done commendable progress in dealing with the above trade-offs.
Async is in Rust can be hard because the problem it is trying to solve is hard.
All the above may be fine but when it comes to choosing the language in practice we need to think of trade-offs and guarantees that are suitable for problem at hand.
There is a reason why C++ reigns supreme in HFT and Gaming as memory safety is not super critical.
Disclaimer: I like Rust.
But it is NOT a good general purpose language. And, maybe to be putting words into the author's mouth, that is their main beef. That every seems to be pushing "Rust All Things" even when it makes no sense, and even if there are much better alternatives available.
So for such comments as "so what about compile time", the issue is that for some, compile time _is a concern_. If it isn't for you, great. But you just can't discount what are valid concerns for others.
People seem to forget that languages are _tools_, and as such, have different sweet-spot use-cases.
Had to buy a new laptop because of this.
I don't think this is correct, strictly speaking. Furthermore, I think this conflates two common causes of slow generic compilation:
- Type-checking them can take a lot of time
- Generics may be implemented in a way that generates a lot of code
Neither of those are required for generics-heavy languages (e.g., OCaml is generally considered to compile fast despite having a "complex" type system), and the presence of one doesn't necessarily require the other - a hypothetical "simple" generics system with heavy use of monomorphization can end up taking a long time to compile, and a "complex" generics system that erases types may take a while to type-check but could compile fast after that.
> Put a non-optional borrow-checker on top of it
From my understanding the borrow checker usually takes up a small fraction of the time needed to compile. There are cases where that's not true, but I think people tend to overestimate its impact on compile times.
> There are ways to implement unsafe programs that still don’t execute remote code or leak secret — they only corrupt user data and act sporadically.
Reliably implementing unsafe programs that don't have RCEs or leak secrets but still corrupt data and "act sporadically" seems like a very peculiar combination of requirements to me, if it's even possible. "Act sporadically" is also quite nebulous, and depending on the precise issue may in fact be an RCE or secret leak in hiding - after all, it's not that uncommon for exploits to start their life as someone noticing a crash.
> It’s probably the strongest point of my whining: Rust is memory safe and unreliable. The price of memory safety was reliability in addition to the developer’s sanity
I think that is actually one of the weakest points. I didn't see any support for a claim that memory safety necessarily requires trading off reliability, let alone that that is what Rust does.
> Step into the shared mutable state — and there a memory corruption is not an exception, it’s a rule. You have to handle the corruptions, you cannot simply crash.
What definition of "memory corruption" is being used here? I didn't think that's the kind of thing that you usually "handle"...
> Which kinda destroys the first uncompromising thing in Rust — performance.
I feel this misunderstands Rust's priorities. (Safe) Rust prioritizes safety over performance, and that has been a well-known tradeoff for basically its entire lifetime. If you want performance at the expense of safety, that is what `unsafe` is for.
> So, to reiterate, the second you step into the shared mutable state you lose every single advantage of Rust. Which is kinda rational considering that the main concept of Rust was to never employ a shared mutable state.
This misses another useful bit of Rust, which is the ability to contain unsafety to clearly-delimited sections of your codebase.
There's more I could say, but life calls...
This complaint is nonsensical. If your Rust program panics, it’s because things are fucked up and it’s not possible to safely continue. The alternative is to continue unsafely, which will fuck things up even more.
The Linux kernel does the same thing. If it encounters an error, it panics.
> Rust sacrificed sanity and practicality for memory safety
skill issue