Note, I am a co-maintainer of GNU coreutils. Whether that makes my opinion relevant, biased, or both, you can decide. :)
I really wished the documented their benchmarking methodology here, or at least cautioned the reader not to jump to conclusions based on the benchmarks shown.
GNU 'sort' performance can drastically be altered by the locale in use, the input, and the arguments given to the --buffer-size and --parallel options. GNU 'sort' is fairly conservative in how many threads it will use by default, and in my experience, much more so than uutils. This is because throwing more threads at 'sort' may make it faster (or may not), but also risks running out of memory. This is an issue with uutils, which is poor at deciding when to use external sorting:
$ export LC_ALL=C
$ for i in {a..z}; do yes $i | head -n $(numfmt --from=iec 512M) | tr -d '\n' >> input; done
$ time sort input > /dev/null
real 0m24.245s
user 0m0.896s
sys 0m19.161s
Here is the same command using the latest uutils commit compiled with 'make PROFILE=release':
$ time uu-sort input > /dev/null
Killed uu-sort input > /dev/null
real 2m53.560s
user 1m40.634s
sys 0m59.847s
The process gets killed by the OOM killer. This is likely because uutils 'sort' decides to use 18 threads, instead of the 1 used by GNU 'sort'. I find it a bit frustrating that benchmarks are thrown out without any methodology or citations, because they are often trusted without question. These could be benchmarks from before uutils had localization, which was the case before 2025, and treated LC_ALL=en_US.UTF-8 as LC_ALL=C. In that case, of course it would be much faster than GNU coreutils, but it also means uutils would give you the wrong results for non-ASCII characters. There is, as shown above, much more considerations beyond speed that seemingly never get the time of day next to flashy benchmarks...
There’s none of those details because it’s an AI written article. It doesn’t even talk about the stuff it says it’s going to in the very first paragraph.
I appreciate rewrite isn't always the answer but it's a strange post when the author should be giving constructive ways forward so we move to Rust and presumably use their own Rust library they link to.
Instead anytime a question is posed it falls back to "sometimes" and little detail after that.
This post advocates rewriting incrementally instead of all at once. Just like Joel said back in 2000, and like everyone continues to always say to this day. Yet in practice, people don't actually do this; complete rewrites in Rust remain far more common than incremental ones, particularly when rewriting from a language other than C. The high-profile exceptions, like Linux, Windows, and Firefox, are codebases so huge and ancient that they obviously cannot be rewritten from scratch. When rewriting from scratch is an option, it tends to be taken.
The reason for this is pretty straightforward: Incrementally porting a codebase from another language to Rust (especially if it's not C) is a deeply unpleasant experience, because the interop tooling isn't good enough and you spend most of your time fighting it. Consider the case of rewriting from C++; in the simplest case, you use bindgen and cbindgen, which only work with extern "C" functions in both languages. So you effectively have to rewrite each API first from idiomatic C++ to C-in-C++, then translate to C-in-Rust, then rewrite again in idiomatic Rust. And then repeat for the next API. And so on. It's not going to take long for most programmers to go "screw it, I don't care what Joel said, at least when I rewrite all my work I'll be doing it in one language where anything can call anything else". cxx and autocxx modestly improve things, but still leave you with an impoverished API vocabulary and similar problems, and you still have to do the three-step rewrite for each API, one at a time.
This is also why TypeScript, Kotlin, and Swift worked so hard to have seamless two-way interop with JavaScript, Java, and Objective-C. Without that, they couldn't have credibly promised to replace the earlier languages (because large existing codebases where a rewrite wasn't economical would still be stuck with them), and so couldn't have gotten off the ground.
Crubit is supposed to fix this for C++-to-Rust, and I'm rooting really hard for it, but it's not there yet. For most other languages, a Crubit-like thing probably isn't even possible in principle, because the differences are too great.
(I'm not talking here about the use case where you started with a garbage-collected language but have hit a performance ceiling with it, so you rewrite just the most performance-sensitive parts in Rust, while continuing to develop the rest of the codebase in the original language. This is often a great way to use Rust, but it's solving an easier problem and so poses fewer difficult tradeoffs.)
> ... Part of this comes from auto-vectorization: the Rust compiler generates SIMD instructions automatically from a regular for loop, while most C implementations require hand-written SIMD...
I understand that their compiler in Rust is better. And any other language could compile it using the same SIMD instructions.
I would love it if jetbrains were to speed up IntelliJ. I started a new job writing Java professionally last year and, up that point, I had no idea that IDE's could actually be that slow.
My company gave me a brand new, beefy Macbook pro and that thing can barely handle IntelliJ sometimes...
There have been times I needed to yell at Claude to rewrite some Python program into a faster lang because it was truly CPU-bound. I chose Rust purely cause of Cargo and the rest of the toolchain, despite being way more familiar with C++ (did use Rust but it was 9y ago). Didn't even care about the borrow-checker for that.
Was just testing latest gen LLM capabilities, and decided to give it goal of rewriting a small opensource project in Rust. (Should be noted: was not some tiny library, but an actually useful network service).
It completed the entire rewrite from typescript to rust in about 2 hours, ~600k tokens used. Worked perfectly on first try with no follow up changes required. Memory and CPU usage now a tiny fraction of TS version (obviously). Rust code was simple, easy to read, accurate test suite, etc.
I was pleasantly surprised.
Obviously bigger code bases with more complex business logic will likely struggle here, but there are some advantages to "RIIR" when performance matters, even security benefits aside. Rust can help squeeze more juice out of old hardware; reduced memory footprint especially helpful with current RAM prices.
For small services where operational cost matters, having LLMs "rewrite it in rust" might be worth the spend.
I’ve seen people do this and I’m always confused, do they believe they will never have to reason about the code ever again.
I suppose if it is like the Zig Rewrite where essentially all development is being done by Claude, I can imagine this making sense.
But in any other case, you had a codebase that presumably you wrote, you could reason about, you could refactor etc. and then you made it into a completely unintelligible code base, which even if written cleanly will take a long time to reason about. Typescript to Rust is not just syntax changes. It doesn’t make sense to me, unless you believe you will be completely out of the loop in managing this code in the future.
To me Rust is great where you don’t have to touch unsafe part. All the hard works are done by those skillful maintainers of the language and some core libraries such as tokio. I don’t see much value in it if either I have to work on the low-level stuff quickly (like implementing linked lists myself) or a complete high-level of i/o bound work like writing web servers.
I think that a line-for-line rewrite in Rust like Bun did isn’t really getting all of the benefits of using Rust. A key benefit is utilizing the type system to make the borrow checker work for you by making certain checks happen at compile-time instead of runtime. Making it impossible for certain mistakes to occur is a massive benefit but you need to restructure everything to do so.
The Bun rewrite is a long-term investment; the idea is that you initially compromise on idiomatic Rust for the sake of being able to keep shipping, but then the codebase becomes more idiomatically Rust-like over time. It will probably take another year or so to determine whether this works out.
(Note also that Bun inherently needs to use a lot of unsafe because a large fraction of its internal API surface is interlinked deeply and pervasively with that of JavaScriptCore.)
> And then there’s the Stack Overflow Developer Survey.
Honest question, at what point is the Stack Overflow Developer Survey not representative of the average software engineer, many (most?) of who no longer use Stack Overflow?
I think every project should seriously ask itself if it actually needs manual memory management. My hunch is that most people who think they need it, do not. If you really truly do need it, then yes Rust is a great way to get most of the benefits of garbage collection while still having manual control over memory.
I wouldn't consider Rust a manual memory environment. There are ways to do that at edges if needed, but it is otherwise very much automatic which is kind of the whole point of its design.
I agree with you, but I just want to point out that there are other seamless solutions to memory management like refcounting, used by for example GDscript (Swift? Perl?). You definitely wouldn't consider this manual memory management
I understand that's a guest post in Jetbrains blog, and these guests could very well be real people, project maintainers, conference speakers and whatnot, but I feel they used LLM so heavily that it reads like a slop. Pease do better next time.
Yes, there are quite a few signs of LLM usage in the post, which I also found annoying. But I also had the feeling that someone really cared about the quality of the text and I found only one strange/useless sentence in the post, which today has to be taken as a win, I guess.
I really wished the documented their benchmarking methodology here, or at least cautioned the reader not to jump to conclusions based on the benchmarks shown.
GNU 'sort' performance can drastically be altered by the locale in use, the input, and the arguments given to the --buffer-size and --parallel options. GNU 'sort' is fairly conservative in how many threads it will use by default, and in my experience, much more so than uutils. This is because throwing more threads at 'sort' may make it faster (or may not), but also risks running out of memory. This is an issue with uutils, which is poor at deciding when to use external sorting:
Here is the same command using the latest uutils commit compiled with 'make PROFILE=release': The process gets killed by the OOM killer. This is likely because uutils 'sort' decides to use 18 threads, instead of the 1 used by GNU 'sort'. I find it a bit frustrating that benchmarks are thrown out without any methodology or citations, because they are often trusted without question. These could be benchmarks from before uutils had localization, which was the case before 2025, and treated LC_ALL=en_US.UTF-8 as LC_ALL=C. In that case, of course it would be much faster than GNU coreutils, but it also means uutils would give you the wrong results for non-ASCII characters. There is, as shown above, much more considerations beyond speed that seemingly never get the time of day next to flashy benchmarks...Oh no, what are we hiding?
> introduces bugs you already fixed.
Isn't this why every bug fix gets a unit test?
I appreciate rewrite isn't always the answer but it's a strange post when the author should be giving constructive ways forward so we move to Rust and presumably use their own Rust library they link to.
Instead anytime a question is posed it falls back to "sometimes" and little detail after that.
The reason for this is pretty straightforward: Incrementally porting a codebase from another language to Rust (especially if it's not C) is a deeply unpleasant experience, because the interop tooling isn't good enough and you spend most of your time fighting it. Consider the case of rewriting from C++; in the simplest case, you use bindgen and cbindgen, which only work with extern "C" functions in both languages. So you effectively have to rewrite each API first from idiomatic C++ to C-in-C++, then translate to C-in-Rust, then rewrite again in idiomatic Rust. And then repeat for the next API. And so on. It's not going to take long for most programmers to go "screw it, I don't care what Joel said, at least when I rewrite all my work I'll be doing it in one language where anything can call anything else". cxx and autocxx modestly improve things, but still leave you with an impoverished API vocabulary and similar problems, and you still have to do the three-step rewrite for each API, one at a time.
This is also why TypeScript, Kotlin, and Swift worked so hard to have seamless two-way interop with JavaScript, Java, and Objective-C. Without that, they couldn't have credibly promised to replace the earlier languages (because large existing codebases where a rewrite wasn't economical would still be stuck with them), and so couldn't have gotten off the ground.
Crubit is supposed to fix this for C++-to-Rust, and I'm rooting really hard for it, but it's not there yet. For most other languages, a Crubit-like thing probably isn't even possible in principle, because the differences are too great.
(I'm not talking here about the use case where you started with a garbage-collected language but have hit a performance ceiling with it, so you rewrite just the most performance-sensitive parts in Rust, while continuing to develop the rest of the codebase in the original language. This is often a great way to use Rust, but it's solving an easier problem and so poses fewer difficult tradeoffs.)
I understand that their compiler in Rust is better. And any other language could compile it using the same SIMD instructions.
My company gave me a brand new, beefy Macbook pro and that thing can barely handle IntelliJ sometimes...
I feel like a lot of the love for IntelliJ is a sort of Stockholm Syndrome combined with relief at not using Eclipse.
(Imho, having cargo available is often already worth a RIIR.)
Was just testing latest gen LLM capabilities, and decided to give it goal of rewriting a small opensource project in Rust. (Should be noted: was not some tiny library, but an actually useful network service).
It completed the entire rewrite from typescript to rust in about 2 hours, ~600k tokens used. Worked perfectly on first try with no follow up changes required. Memory and CPU usage now a tiny fraction of TS version (obviously). Rust code was simple, easy to read, accurate test suite, etc.
I was pleasantly surprised.
Obviously bigger code bases with more complex business logic will likely struggle here, but there are some advantages to "RIIR" when performance matters, even security benefits aside. Rust can help squeeze more juice out of old hardware; reduced memory footprint especially helpful with current RAM prices.
For small services where operational cost matters, having LLMs "rewrite it in rust" might be worth the spend.
I suppose if it is like the Zig Rewrite where essentially all development is being done by Claude, I can imagine this making sense.
But in any other case, you had a codebase that presumably you wrote, you could reason about, you could refactor etc. and then you made it into a completely unintelligible code base, which even if written cleanly will take a long time to reason about. Typescript to Rust is not just syntax changes. It doesn’t make sense to me, unless you believe you will be completely out of the loop in managing this code in the future.
(Note also that Bun inherently needs to use a lot of unsafe because a large fraction of its internal API surface is interlinked deeply and pervasively with that of JavaScriptCore.)
Honest question, at what point is the Stack Overflow Developer Survey not representative of the average software engineer, many (most?) of who no longer use Stack Overflow?