> So you haven't understood the distinction or you're letting your feelings for software get the best of you.
Maybe? I'm not sure.
> The proof that there are no (for rust's definition of "no") memory bugs becomes worthless
I still don't think so, the proof that there are no memory bugs is definitely not worthless, since while the whole proof itself is binary (it is either fully correct or not), its effects act more like coverage, and the more of it that happens to be partially correct, the better.
I think cve-rs is the perfect example of this. Its very existence proves that the borrow checker is already unsound, and with that, the very foundations of Rust's safety guarantees are currently flawed.
TypeScript is another good example, its type system has been repeatedly proven to be unsound, so it's also flawed.
But so what if it's flawed? Many smaller properties of these proofs still happen to hold, and they might prevent 90%+ of CVEs even as flawed as they are.
But code is not mathematics, so incorrect code is not worthless, it’s just worth less.
It’ll most likely still do 99% of the things people need it to do, there’ll be a an issue created for that broken 1%, and eventually it’ll be iterated upon and fixed.
Unless you’re working on a security boundary of course, there you should treat it like maths.
Only ~4% of code is inside an unsafe block, so the idea is that for new code/contributions, the chance of introducing a new memory-safety bug is an order of magnitude lower.
Maybe in the future the unsafe code will go down to 1%, bringing that to two orders of magnitude.
Of course, only time will tell if that is true or not, but from experience I’d be willing to bet it is.
If cve-rs exists, we still say that safe Rust is safe, in the same way that we say Python is safe despite potential bugs in its interpreter or native libraries, and that Java is safe despite potential bugs in the JVM or JNI libraries, and so on.
> "unsafe" is in practice often needed for performance in Rust
That's the power of Rust, not a limitation of it. Rust thrives on its ability to provide safe interfaces over unsafe code.
You'll see this practice in other languages too; if you're coding safe Java, you're using a lot of unsafe code from the JVM and via JNI.
If you're using Python, the stdlib and all the performance-sensitive libraries (numpy, pandas, etc) are written in unsafe code, but even when you import those we still say your Python code is safe, and that Python overall is a memory safe language.
> honestly thats the biggest problem with rust, they come up with a lot of useful changes but then take ages to stabilize because the core team is overworked
On the contrary, that has been one of Rust's biggest strengths. My impression when reading through stdlib was that they got so many things right, and for that to happen, things need to be thought out properly.
Case in point, it'd be such a shame if they stabilized the allocator API, only for us to forever regret never getting the storage API [1] instead, or vice-versa, depending on which one turns out to be more pragmatic.
> they also have a kind of perfectionist culture as a reaction to all the half baked features shipping in C++.
And that's a good thing! Some people really dislike the constant influx of new features due to the overwhelming complexity it leads to. So if we do have new features, they better be worth it.
GP is referring to the article's title, as in "safe Rust", as in "Rust with no unsafe keyword", as in whether it has undefined behavior or not.
Granted the premise is rather brittle, since all Cpp2Rust does is to convert UB to runtime crashes, which can be undecidable, and cannot be used to prove anything about the original C++ code.
It is a fundamental language limitation, unless you want to claim that the core library (or rather what's left when using no_std) is not part of the language.
The problem comes from a combination of three things:
1. Rust's standard library (including core) likes to panic a lot, e.g. for code that is genuinely unreachable (and this is fine)
2. Rust/LLVM cannot always optimize unreachable code away (and this is also fine)
3. The presence of at least one panic causes Rust to also include the error string format machinery, which is HUGE (and this is completely unavoidable)
Because of #2, there is no way to prevent this for larger code. I can define my own panic handler, but I can't prevent panic!() calls from inside core from constructing the format message using core::fmt before they call my panic handler.
And so any non-trivial code sometimes just randomly becomes 3x larger, and I can no longer fit it on my MCU, despite never actually printing or caring about any panic messages.
I tried to use Rust for a tiny microcontroller (GD32VF103, 128KB flash).
First of all, I was amazed by how much I could do with Rust (safe Rust, even), and how well it was interfacing with my handwritten RISC-V assembly. I will definitely use Rust again for the next such project.
But, every time my functions would get over a certain size, suddenly some optimizations stopped working, and Rust was trying to put the whole panic/fmt machinery into the thing, going above my linker's flash size limit. It was insanely frustrating, since there was no rhyme or reason to it. Simply adding another branch to a match made it do that. Or another if statement that was exactly the same as the 4 before it.
Languages, no. But for language-agnostic package managers, Nix/Guix and Gentoo are similar.
Sadly, Gentoo is not great for managing per-project dependencies in the same way as is done by npm, pipenv, etc. Nix however works great (if you can stomach its stdlib).
Ah, okay. In that case I feel like the only sane way to approach this is to completely abolish null-terminated strings, and reimplement everything (including stuff like printf's format and arguments) in terms of strv. Otherwise if there has to be a 2cstr function, it should be an allocating one.
> The concept of "a garbage-collected language" is not well-defined. There are languages, like Java, Rust, and Python that depend on a garbage collection mechanism, and languages like C, C++ and Zig, which don't. C++ happens to offer a GC in its standard library, however.
How does Rust differ from C++ in this regard?
As far as I know, both use RAII, and offer something RC-like in their stdlib that is optional to use.
The list of features and anti-features looks amazing, that's just want I want from a simple systems language.
However, the list of examples has... basically nothing. So it hasn't really proved that its set of features is enough to do anything with it.
The syntax is... off-putting. Regardless of how superficial it might seem, most systems programmers will want curly braces, and going against that is a really bad idea.