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.
> 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.
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++:
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.
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.
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.
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.
> 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.
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?
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.
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.)
> 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.
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.
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.
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.
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.
55 comments
[ 3.2 ms ] story [ 128 ms ] threadAll 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
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.
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
Just search for the various revisions,
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/
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.
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.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p26...
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.
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.
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.
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.
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.
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.
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.
But what happens to inbound references when I'm moving my object? Who is in charge of updating them?
Can rust generate usefull machine code without a runtime and having to break one leg like C?
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?)
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.
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.)
Can I do the same in rust?
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++.
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.
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.
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.
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.