Most active commenters
  • tucnak(5)
  • junon(4)

←back to thread

128 points RGBCube | 14 comments | | HN request time: 1.598s | source | bottom
1. tucnak ◴[] No.44497968[source]
A bit off-topic, but every time I read some sophisticated Rust code involving macros, I cannot help but think that something went wrong at some point. The sheer complexity far outpaces that of C++, and even though I'm sure they would call C++ on undefined behaviour (and rightfully so) it seems less of it has to do with memory and thread-safety, and moreso with good old "C++ style" bloat: pleasing all, whilst pleasing none. Rust doesn't seem worthwhile to learn, as in a few years time C++ will get memory safety proper, and I could just use that.

Maybe this is an improvement on templates and precompiler macros, but not really.

replies(4): >>44498048 #>>44498102 #>>44498299 #>>44499269 #
2. junon ◴[] No.44498048[source]
None of this has to do with the complexity of macros.

And no, sorry, the complexity of C++ templates far outweighs anything in Rust's macros. Templates are a turing complete extension of the type system. They are not macros or anything like it.

Rust macro rules are token-to-token transformers. Nothing more. They're also sanitary, meaning they MUST form valid syntax and don't change the semantics in weird ways like C macros can.

Proc-macros are self-standing crates with a special library type in the crate manifest indicating as such, and while they're not "sanitary" like macros rules, they're still just token to token transformers that happen to run Rust code.

Both are useful, both have their place, and only proc macros have a slight developer experience annoyance with having to expand to find syntax errors (usually not a problem though).

replies(1): >>44498432 #
3. coldtea ◴[] No.44498102[source]
>The sheer complexity far outpaces that of C++

Not even close. Rust Macros vs C++ templates is more like "Checkers" vs "3D-chess while blindfolded".

>Rust doesn't seem worthwhile to learn, as in a few years time C++ will get memory safety proper

C++ getting "memory safety proper" is just adding to the problem that's C++.

It being a pile of concepts, and features, and incompatible ideas and apis.

4. j-krieger ◴[] No.44498299[source]
I write both for a decade now and I disagree immensely. If Dante knew of the horrors of CPP template compiler errors he would've added an eighth ring.
5. codedokode ◴[] No.44498432[source]
Proc macros are implemented in an unsafe way because they run arbitrary code during compilation and access any files. I do not like it.

Also I think it would be better if they operated with reflection-like structures like functions, classes, method rather than tokens - they would be easier to write and read.

replies(2): >>44498561 #>>44499088 #
6. junon ◴[] No.44498561{3}[source]
I agree in principle but also there's a lot of worth in having them do that in certain cases, and build scripts and the like already have that anyway.

Achieving a perfect world where build tooling can only touch the things it really needs is less of a toolchain problem and more of an OS hardening issue. I'd argue that's outside the scope of the compiler and language teams.

7. tucnak ◴[] No.44499088{3}[source]
This is often overlooked. No, I don't want random cargo package to run RCE's on my machine. And there's just so many; in terms of bloat, the dependency trees are huge, rivaled only by Nodejs, if I'm being honest. I have to build some Rust stuff once in a while (mostly Postgres extensions) and every time something goes wrong it's a nightmare to sort out.
replies(1): >>44500772 #
8. bigfishrunning ◴[] No.44499269[source]
I'm convinced that the only reason anyone's still using C++ is that they refuse to learn any other language, and the features they want may get added eventually. C++ is an absolute mess.
replies(1): >>44500977 #
9. junon ◴[] No.44500772{4}[source]
I never have these issues. Is the postgres driver a C wrapper? that's where things tend to fall apart.
replies(1): >>44501275 #
10. tucnak ◴[] No.44500977[source]
Rust is clearly aiming to match C++ in complexity.

I don't know whether this is “Death by committee” in a new wrapper, only this time it's the "community," driven by Github emojis, as opposed to legacy processes you would find in C++ committees. Upon closer inspection, there's so much more in common between the two than it would seem! The most glaring difference is cadence. C++ is evolving slowly, and the newer stuff is not rushed into codebases. Rust projects are commonly staying on the very latest stable releases, & in some instances, nightly builds—to compile. I primarily interact with Rust codebases in the context of Postgres extensions, and I can tell you one thing: constantly having to update Rust toolchain to keep my databases up to date is a _massive_ chore.

Curiously, it would appear that the niche Rust is occupying nowadays has very little overlap with C++ applications, and so much more overlap with C. We're beginning to see more and more of Rust creeping into C projects. Meanwhile, the not-so-recent addition of smart pointers, coroutines, and the more recent improvements on these designs have allowed C++ codebases to evolve at predictable, clearly-defined pace. There's definitely a battle for C++ mindshare going on, and it's really not been good outcomes for Rust people. I'd like to remind you that most large-scale orgs where performance and stability truly matters, are still overwhelmingly C++. The HPC world basically runs on C++. The AI landscape, that is, you could make an argument, merely the extension of HPC—is similarly dominated by C++. CUDA is fundamentally an extension of C++. The larger CUDA toolkit and programming guides primarily use C++ syntax and features. Legacy? Sure. This is also the case for the majority of emergent projects in the field, including ROCm, JAX, Tenstorrent stack, and consequently the vast majority of higher-order frameworks such as llama.cpp, torch, vLLM, TensorRT—all rely on C++ compilers. Rust is virtually non-existent here, which was surprising to me originally, as I would expect Rust people to be interested in homogeneous computing, but it's started making sense when I looked at Rust-CUDA compatibility matrix.[1] Turns out, it doesn't really support anything useful for performance, and the things that it does support—all have asterisks next to them.

The Rust community is obsessed with a handful hyper-important projects, such as Linux kernel, Android, Postgres (via pgrx[2], where it has been incredibly useful!) etc. IMHO, this is very telling, & a part of the larger strategy. Ignore, or re-write small projects with no intent to maintain them later, abandon the more ambitious Rust-native projects, and focus on some of the most high-profile C projects with sufficiently-large surface area, where memory safety has traditionally been a problem. You could make an argument that Linus Torvalds is, frankly, exploiting Rust evangelists, and avoiding any bad publicity that denying them completely would entail, instead opting to direct their energies towards the most boring stuff possible: the driver subsystems. This is changing, of course, most notably with bcachefs (Kent is very fond of Rust!) and we have recently seen how that played out.

The Rust Foundation needs to think about optics; it doesn't look good at all.

On the other hand, I've grown to appreciate, and indeed, tempted to write some simple programs for Xous[3], of Precursor fame, which is a really nice bit of kit, and cleverly designed, too. (See pddb[4] work by bunnie circa 2022, it's really quite exciting!) Honestly, this is Rust at its best: a Rust project written from scratch, for good, technical, no-bullshit, no-compromise reasons where it matters the most, and actively maintained, too. Although with the return of memory tagging technology (pioneered by IBM in the 90's) in Arm v9, formally-validated CHERI designs, I'm not yet convinced Rust itself provides enough oomph, hype notwithstanding, to justify much wider adoption. It's been 10 years since Rust 1.0 and the wider industry adoption is otherwise quite underwhelming. They're no longer the new kid on the block; in view of "speedrunning" feature cadence, most notably culminating in the whole async debacle—it's not looking good at all. The Rust Foundation is routinely exploited by big corps in the stark-naked pursuit to harvest young talent, but other than a few small, hyper-useful applications, like ripgrep, alacritty, a few Rust-only shops (Oxide?) and activism largely directed towards legacy C projects, recognised by StackOverflow as "the most loved language" who knows how many years in a row, industry-wide adoption really has been lackluster _at best_.

Contrary to popular belief, C++ is getting easier on the eyes as years go by, at the same time Rust is only getting harder to read. I really liked the direction they originally took back in 2014, but they're now far beyond the point of no return; the proc-macros and arcane cargo mechanics, are only making the matter worse. If I were a betting man, I would predict that C++ will eventually incorporate most of what makes Rust great: borrow-checker, and many alternative approaches are floating, & gaining traction. The static analysis and perf-class tools have come a long way. Fuzzing, too. Modern C++ is already very different from C++ of 10 years ago, and many orgs choose to only use a specific subset of it. The same is happening in async Rust, but the larger language and tooling design doesn't lend to "siloing" as well. I personally stopped writing C++ professionally for 5 years after I stopped contributing to KDE projects, and when I came back to learn about lambdas, smart pointers, move semantics and all, it was quite straightforward. The amount of tooling that C++ had accumulated during this time is quite staggering, and their traction speaks for itself.

In 2025, more C++ is being written than at any time in the past, and young people are learning it, too. To them, from POV of "Modern C++" a lot of arguments Rust people are making—seemingly falls on deaf ears. If C++ were the dominant ideology, and Rust the subverting one, it's clear that the former is set on incorporating the latter in its discourse. What usually happens in such scenarios is longterm it boils down to taste. IMHO, in matters of taste, C++ is more flexible (to agreed-upon subsets) than Rust could ever allow today, and I struggle to see how this asymmetry could be reconciled; there is seemingly no appetite for it in Rust circles outside of async runtimes.

EDIT: Don't forget about LLM technology! There's orders of magnitude of C and C++ code of various styles around. The primary selling-point of Rust is that it enables memory and thread-safety, right? If the sufficiently-advanced AI agent runtime is able to troubleshoot and address them in time, it would become much less of an issue. Many security companies are already using LLM tooling to catch various vulnerabilities, and sometimes even bother the maintainers with it, demanding CVE's assigned and all. There was a thread on HN recently covering this topic. The agent runtimes have dabbled in super-optimisation and even writing highly-sophisticated fused kernels; guess what language it's all been done with?

[1]: https://github.com/Rust-GPU/Rust-CUDA/blob/main/guide/src/fe...

[2]: https://github.com/pgcentralfoundation/pgrx

[3]: https://github.com/betrusted-io/xous-core

[4]: https://www.bunniestudios.com/blog/2022/the-plausibly-deniab...

11. tucnak ◴[] No.44501275{5}[source]
Yeah, they would often claim that C API is at fault, but believe it or not, blaming Rust just as much. I've had an interesting discussion with pgrx people: https://github.com/pgcentralfoundation/pgrx/issues/1897#issu... to quote @workingjubilee

> Rust has formally rejected the notion that any function can return twice. Even LLVM has no special knowledge of the name of "sigsetjmp" or "setjmp", only that some functions can return twice.

> Thus, when you call sigsetjmp or setjmp from Rust, Rust doesn't believe that you called a function that can return twice. The Rust compiler refuses to annotate it with the required LLVMIR annotation. Thus LLVM sees a call to sigsetjmp that it believes cannot return twice... it's just an ordinary function that someone named "sigsetjmp" because they have a sense of humor. What LLVM does next is between itself and whatever gods that compilers believe in, and we have no more voice in such a matter.

In this particular case, it's hardly the fault of a "C wrapper."

replies(2): >>44502152 #>>44502552 #
12. tialaramex ◴[] No.44502152{6}[source]
Sure looks like it is, indeed, a C problem. Which checks out with my experience, the only time I had a crate fail to build in all these years it was C underneath and of course C is just anything which happened to compile and seemed to work. As an ex-C programmer I guess I sympathise, none of the non-trivial C I wrote 10-20 years ago actually builds out of the box on today's systems that's just how C is, so why would Rust magically fix that.
13. junon ◴[] No.44502552{6}[source]
I mean... yeah? Rust explicitly doesn't allow longjmp or related machinery, at least not in any way that works well with the Rust VM.

And for good reason. That's been a wart and a hack since the day it was created. I'd say this is a _good_ thing.

replies(1): >>44502734 #
14. tucnak ◴[] No.44502734{7}[source]
My issue with it at the time had to do with... how to put it... simply build the extension, & carry on with my life. Version after version it would build alright, and then suddenly, boom, it doesn't work no more. Okay, I understand that perhaps ppc64el is not the most popular architecture, and some things aren't easily portable, but this otherwise mirrors my experience with Rust programs. It's always requiring the latest version of everything. The recommended installation path involves sudoing shell scripts over network, and I'm sure Rust people love it, salivating over new versions and features that come along, constantly staying up to date, but to the rest of us normal people dealing with Rust software is a chore.

Cmake is a huge quality-of-life improvement all things considering!