55 comments

[ 3.2 ms ] story [ 128 ms ] thread
Rust is a subset of C++ with extra static checks.

All the core decisions are the same as in C++:

- RAII

- Lock-based concurrency

- In-place mutation

People get confused when they hear that Rust is 'related to ML' and has Refs, but Rust Refs have nothing to do with ML Refs: ML Refs are mutable pointers to immutable data, Rust Refs are pointers to data mutated in-place.

Reference counting is not 'Rust memory management' it's a well-known technique with well-known problems, and Rust doesn't bring anything new to the table here.

Edit: RIAA -> RAII

> Rust is a subset of C++ with extra static checks.

While this may work as a rough heuristic, it's not true in theory nor in practice. First example that comes to mind: Rust has proper sum types (Called enums), which are used everywhere, and C++ doesn't have anything like it.

As far as I've seen, std::variant's ergonomics isn't remotely competitive with rust sum types. C++ lacks the syntax.
Yet they're both conceptually the same old thing: tagged unions.

In C++ everything is just more awkward since everything is bolted on as an afterthought in the stdlib but then lacking language syntax sugar to make its usage convenient.

E.g. the (somewhat weird looking) equivalent to Rust's match is called 'visit' in C++:

https://en.cppreference.com/w/cpp/utility/variant/visit2

I can create tagged unions in literally any language not just C++ including Assembly. Rust having syntactic and compiler checked support for them as a foundational part of the language is a material difference in the design that differs fundamentally from C++. So the the point still stands.
Syntax is on its way...
Source?
There are at least three proposals in flight for C++26, if they reach an common agreement on time, or it has to be done by C++29, remains to be seen.

Just search for the various revisions,

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/

I'm not even using Rust but I think you should stop hyping things that won't exist for years as if they were real and proven, like you've been doing a lot.

I've had a quick look at one of the proposals behind the link and it's no comparison with the existing Rust way. Even std::variant itself is a crutch (being templatized by a list of types), not comparible with true algebraic datatypes.

`std::variant` is a clever piece of template hackery, but it doesn't come close to Rust enums. `std::variant` has no named variants, no pattern matching, no exhaustiveness checking. In Rust, it's not unusual to have an enum with dozens of variants, good luck doing that with std::variant.

I'm sure you could technically emulate all this in C++ is you keep throwing template metaprogramming at it, but at that point anything is a C++ subset and the statement loses all pratical meaning.

Pattern matching is on its way, one of the possible approaches being discussed,

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p26...

Coming right after profiles are done, probably?
One has nothing to with the other.

That is the thing with committee driven languages, with multiple vendor implementations.

Not everyone is on the same room voting for the same features, and not everyone is implementing the features in any specific order.

By the way, I would rather have Safe C++ than profiles, but do not vote, so whatever.

I'm not saying they are related, just saying that the committee committeing is going to take half a decade at least for both.
Well, it is still going to be faster than WG14 ever doing anything useful improve the C's security model regarding arrays and strings.

It has hardly moved since 1989, and annex K doesn't count, given its broken design.

Anyway I am still mostly stuck with .NET Framework, Java 17, node 20 in many commercial deployments, so it isn't like everyone cares that much to update to latest, given existing business decisions.

Those kind of industries don't care about programming language featurities anyway.

I understood your joke, but we just found out a few hours ago what happened in Hamburg, and while neither of these features made it yet, they're seemingly going in opposite directions:

pattern matching had a poll in forwarding to the CWG, and it was mostly in favor, though enough were against it to not reach consensus

profiles had a poll in forwarding to the CWG, and it was split down the line in terms of for/against.

Given the previous votes on profiles being nearly unanimously for, I'm interested to see what people have to say about what went on.

I don't even think Bjarne could claim with a straight face that hacking variants into the standard library was a good idea :)
He only gets one vote among 300 something committee members, so his opinion while important, is largely irrelevant.

By the way, ever noticed that after C89, neither Ritchie nor Dennis ever had anything else to do with how WG14, or the compiler industry vendors, decided to take C onwards?

The original Plan 9 C compiler isn't even standards compliant.

And this has what to to with variants?
Bjarne's opinion on variants hardly matters to WG21 working process.
What are you even talking about?
Also the move semantics of rust completely change how you reason about variables.
recently learned that move semantics in C++ leave the moved-out object in this weird state... and this after almost 25+ years of using C/C++ - lol....
I believe you mean RAII. Though I suppose I've seen no evidence against the notion that Rust likes the Recording Industry Association of America.

Jokes aside, I think the biggest difference between Rust and C++ lies in metaprogramming and generics. Rust macros are a trip.

Rust's sum types and traits are also much more deeply integrated into the syntax of the language than std::variant or concepts.

Thanks for spotting the typo :)
> Rust is a subset of C++ with extra static checks

This is like saying that Julia is a subset of Python with JIT compilation. Rust and C++ have some conceptual similarities, but they are entirely different languages.

> All the core decisions are the same as in C++

Not at all. In a Rust program, all objects are supposed to be movable via a memcpy (i.e. a bitwise copy) by default. Immovable objects are only supported as an afterthought, via the Pin<> featureset (which is widely regarded as unintuitive, clunky and in need of revision). C++ objects are immovable by default; alternately, they may support custom "move" operators that are closer to the way .take() is used in Rust, i.e. they leave behind the original object in some sort of undetermined state.

These are quite significant differences that make it hard to have consistent interop across both languages.

This is interesting. If I want my object to be movable without the need for acquiring the locks for all outbound references, I need my references to be of type 'reference to mutable data'. So that could be one of the reasons why Rust reference types are like this.

But what happens to inbound references when I'm moving my object? Who is in charge of updating them?

You get a compile time failure. There is no mechanism to automatically update them.
Ok, I see now. This is limited to cases when compiler can prove that the reference is not shared, but still can be useful when adding elements to collections.
Yeah, among other things. It can be used to implement “session types” which basically means encoding a state machine in the type system. So for example, I’m building a web application at work, and users have permissions to access resources. The “please grab a foo from the database” function takes an Authorization as a parameter by move, so in order to call it I have to get one. The only way to get one is to ask the auth subsystem, which checks if a User has the proper permissions. And the only way to get a User is to ask the auth system to authenticate that they have a valid session. So as long as I make my “fetch resources” code require an Authorization as a parameter in the future, I’ll also guarantee that all of the rest of that stuff happens. It’s a little verbose but pretty cool.
(comment deleted)
I want to have fine-grained and full control over memory management.

Can rust generate usefull machine code without a runtime and having to break one leg like C?

> I want to have fine-grained and full control over memory management.

Rust's global allocator is easy enough to replace on stable: https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html

Per standard container allocators ala C++'s std::allocator haven't been stabilized, but are available on nightly: https://doc.rust-lang.org/std/alloc/trait.Allocator.html

Alternatively, you can roll your own allocator ecosystem easily enough - my limited foray into this is mostly focused on interop with specific 3rd party allocator APIs from C, C++, Win32, etc.: https://docs.rs/ialloc/ , there are plenty of crates focusing on arena allocation etc. instead.

> Can rust generate usefull machine code without a runtime and having to break one leg like C?

Yes.

At one extreme, you can create #![no_std] crates ( https://docs.rust-embedded.org/book/intro/no-std.html ) which don't assume you can create threads, write to stdio, or even allocate heap memory. I've gotten Rust static libraries linking into "unsupported" platforms in minutes (when it had an LLVM-compatible linker available.)

At the other extreme, I've previously ported Rust's standard library to an unsupported NDAed platform. It's easy to stub out unsupported bits - the code for such stubs already exists to support wasm32-unknown-unknown (arguably a mistake, but it's a useful one!) - and replacing those stubs with real code isn't too onerous in my experience either.

Middle grounds of `extern crate alloc;` let you support subsets of "the standard library" as well.

Yanking all "runtime" support out of existing platforms might be a bit trickier (e.g. there's a little code to support populating std::env on *nix, a little mucking with default signal handling, and e.g. windows builds will use Win32 APIs for backtracing and unwinding for panics - ripping that all out is more obnoxious, but also pointless IMO.)

Some non-NDAed examples of targeting funky stuff:

https://github.com/MaulingMonkey/uefi-hello-world (why write hello world for windows when you can directly boot hello world?)

https://github.com/MaulingMonkey/rust-opendingux-test (old, linuxy - see Notes.md, consider using -Zbuild-std instead of Xargo these days?)

> Can rust generate usefull machine code without a runtime

Afaik, the only runtime parts of Rust are panic handling, standard library and thread management.

You can disable the standard library with `#![no_std]`, and I'm fairly sure you can also disable the panic handling (but not 100%) and I don't know if you can disable thread management at all. But if you can, I think you can have what you're asking for :) Edit: In fact, the `no_std` might actually disable all of the above, not just the stdlib.

> thread management

Note that the "runtime parts" in question here refers to initializing OS-level threads, the same as in C. It's not referring to any sort of userspace green thread runtime (which you would need to bring in yourself).

no_std disables the parts of the standard lib that rely on having an OS (e.g. threads) or having an allocator. (You can get the allocator parts back in a no_std program if you define your own allocator.)

"Panics" aren't something you'd disable, a panic is just a mechanism for crashing the program in a controlled manner. Rust lets you decide whether or not you want panics to abort the program immediately or whether to unwind the program and run destructors, and you can configure this in any Rust codebase via a config key/compiler flag. (If you're using no_std then you can technically also define panics as being an infinite loop, rather than crashing.)

I would call Rust comparable to C when it comes to giving you the ability to have control over memory management and machine code. Which is to say, if you have a problem with how C does it, then I doubt that Rust will make you any happier in this regard. What pain points in C is this referring to specifically?
I think you need to specify what you mean by "without a runtime". Do you mean "without a garbage collector"? "Without memory allocation"? Even C has a runtime, just a very small one.
I am talking C without any runtime: machine code or data are _ONLY_ from the C code (and OS interaction is done with raw syscalls).

Can I do the same in rust?

Yes.
Getting mixed signals about this.

Lies are flying all over.

I'll need to check that by myself one day.

What's seems to be really sure though is the filth of rust syntax complexity on par with the other filthy one, c++.

The smallest binary rustc has ever spit out is like 137 bytes.

It has the exact same amount of runtime requirements as C. The default configurations aren’t optimizing for size, but if you want to strip it down, you can.

You will always have Assembly for driving dangerously fast without either a seatbelt, nor an helmet.

By the way, even C has a runtime, without which several ISO C features aren't available.

That is why there is a freestanding section.

So it means rust cannot do that. Ok, next.
It definitely can, I decided not answer that.

For example, Microsoft has thrown away all their C code on Pluton CPU firmware and replaced it with Rust.

Likewise Google has been shipping Rust on Linux kernel downstream fork on Android for several versions now, regardless of upstream drama.

And any recent Windows 11 version runs Rust kernel code, every single time anything on the screen, after the GDI regions handling C kernel code has been rewriten in Rust.

The cargo cult that C is the be all, end all of systems programming gets tiresome after a few decades.

If you think google and microsoft are good examples, good on you :). That said... I have been having seriously mixed signals about this.

In the end, I'll have to check that by myself to get a final answer to who is lying here. And there is already an issue with rust: its toolchain cannot statically link libgcc (bug since 2015?!).

And it seems rust syntax has the same toxic complexity than the filthy c++ one which would make it a definitive nono for many.

They definitely are, more than most of us on HN ever dream to achive leaving our mark on the industry.
They are certainly not... you better cherry pick and get deep into the details... where it lies...
"Rust memory management explained" (excluding borrowing) is TBH wild. Without borrow checker Rust safety guarantee is nothing new
There are many other posts like this, I struggle to see what this one brings to the table. To understand how Rust manages memory, one should refer to the rust book instead - it will be a richer explanation originating closer to the source.
It is the Rust's version of the Haskell's burritos blog posts of 15 years ago, every time someone finally understood the M word.
(comment deleted)