I've been thinking of migrating from C to Rust, but with unsafe Rust I can't see much benefit as it's much less well defined than C from what I can see.
The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust’s semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe.
Breaking the pointer aliasing rules. The exact aliasing rules are not determined yet, but here is an outline of the general principles
Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented.
There's not many guides online about how to write unsafe Rust either, mostly 'it's really hard and you shouldn't do it'.
I've already read through the Rust documentation, the Rustonomicon and several other resources to try and understand what I'm suppose to do when writing unsafe code. But most if not all of them are incomplete and make few promises about future behaviour. So if my code in unsafe Rust works today and seems sound today, tomorrow it might be completely unsafe and crash my machine.
The caveats in the Reference are largely because the work to precisely define Rust is not done — in practice, it is entirely possible to write useful unsafe Rust code that is within the bounds of what has been promised to be sound (significantly by std documentation, not the reference).
When comparing the risk of writing unsafe Rust to the risk of writing C, you have to consider the pragmatic outcomes, not just how good (well, existant) the specification is.
When writing Rust, you can and should write mostly safe Rust, with unsafe code confined to small modules that do narrow tasks with care. When writing C, there is no safe mode and a mistake anywhere in the program could be disastrous.
Much of the C code actually out in the world is unsound according to the C specifications, and often “works fine” despite that. The C people actually use is not exactly the C that is specified.
The vibe I'm getting here is less that there is a correct way to write unsafe Rust and more that unsafe Rust is a tool for limiting how incorrect your code can be?
also, I would like to remind the purpose of unsafe rust is to compensate the limitations in safe rust. it's definitely NOT a replacement for C, and it can't be.
there was similar discussions recently on this forum (for entertainment):
It does seem like that consensus is that Rust can't replace C and I've misunderstood the purpose of unsafe Rust. I think for now I'll stay writing C and wait until there's better tools out there.
No. The entire point of my linking to Tsoding's video was to demonstrate that Rust can be used exactly like C. If I remember correctly in that threat I present a linked list written in the "crust" style that looks line for line like a C linked list.
Note: The video title "What if Rust was Worse than C" is a click bait title and a fine example of Tsoding's sense of humour. And of course the rules of "crust" programming are to be taken with a smile as well.
Anyway, the proof is in the pudding. If Rust with "unsafe" could not be a replacement for C then people would not be able to write operating systems and embedded systems with Rust. But they do, so it is.
Would you tell someone coming from handwriting x86 assembly that they should learn C because "you can just write inline asm, then it's the same language"? I hope not. For the same reason, I hope you don't tell people to learn Rust because "you can just write it like it's C". It's technically kind of true, but horribly misleading.
I believe you should learn Rust because its features make C largely obsolete. A lot of the tricky skills expert C developers learned are hard-coded in the language, empowering you as a developer to focus on the actually important parts of software design. If you don't want those tools, if you're just looking for a fresh syntax for C, then please don't learn Rust. It'll be a waste of your time, and frustrating to boot. If you really just want another C/C++ clone, take a look at Carbon or D.
And yes, unsafe Rust has more (or at least, other) caveats than C. You have to remember that unsafe Rust isn't in a vacuum: it must interact with safe Rust, which is hopefully the vast majority of Rust out there. That border carries a lot of uncertainty and danger. You must ensure that your unsafe code cannot cause UB in the hands of safe Rust, and there's a lot to be considered there. In C, the ecosystem is old enough that most of the common gotchas (such as thread-safety) are avoided simply because the problem areas are avoided (such as most C programs are single-threaded).
So while yes, Rust has a plethora of advantages that you and I believe make it better than C, it does not make its a "better C".
I certainly have never said that. That whole thing about writing Rust as if it were C is done in humour. I guess one would actually have to watch Tsodings video to appreciate that. I recall putting disclaimers in my thread about it just in case people did not get the joke. Seems people still did not get the joke.
I would not claim that Rust is just a "better C". Rust is its own language. I will claim Rust can be used to good effect, same performance, same code size, same results, wherever one would have previously used C. With the great advantages Rust brings in improving correctness.
Rust can do what C does, but also it can be used without unsafe, and probably 99% of Rust code does not use unsafe, you only use it in very rare circumstances where you are making some low-level container, or interfacing to other languages. When you do that, in most cases you can test with Miri, which catches memory safety issues. So most people now write new system software in Rust rather than C, it is more expressive and doesn't suffer from memory management errors that are common when using C and C++.
Remember that this quote is fully applicable to C and C++. DR260 is still not reflected in any standard after two decades.
I, for one, would rather work with the language that admits that problem exist than with language that pretends for decades that problem simply doesn't exist if documentation doesn't talk about it.
Do you have some unsafe code you wrote whose soundness is unclear or is this a hypothetical concern? What are the kind of things you would be using unsafe Rust for?
It is very easy to get it wrong, the main rule is you have to respect the rules of references. But there is an interpreter tool called Miri which allows you to test and check you haven't blundered. However mostly you do not need to use unsafe at all, so that is not something to worry about.
I think this comes down to some cultural difference in the C standards committee and the Rust Project.
In the C standards world, they look at a problem, think about it for while, and they make a decision, and if it's the wrong decision it can be revised in the next edition of the standard. In Rust, they seem to strive not to have to make such corrections, so they opt for kicking the can down the road instead when they aren't sure what the proper forever path is.
(If you're worried that these specification gaps are things the Rust project ignores, then you can dispel this fear by reading the rust-lang zulip).
Also, if you look around you can find people needing to do work in these underspecified areas, and the project is generally helpful in finding ways to solve whatever issues arise. It's not like everything that is under-specified is also completely unknown; sometimes they have a pretty good idea where things will land, but they just aren't 100% sure yet and thus aren't willing to commit to it (in writing) yet.
Sometimes you have to do that. And then, when in doubt, you have to ask experts, compiler guys and others about whether what you wrote is sane or not. But the issue is that with C/C++ it's the same thing! And I say that as someone who have filed quite a few issues in the gcc and clang repos (some in rustc, too) — some of them were rejected, because my code was “wrong”, about one per couple of years is accepted (with bugfixes in all three: clang, gcc, rustc)… for all the assurance that it's enough to simply buy the C or C++ standard and then follow it… the reality is different.
Rust simply accepts that reality while C/C++ world, usually, lives in denial. And the first part of Rust's acceptance of the reality is usafe keyword itself: it's there to signify that you are doing something “strange”.
Compare to C/C++ where “tricky code” is only marked with comments… if it's marked at all.
Most of these discussions stay very abstract compared to equivalent discussions in C/C++.
Rust has two modes, safe and unsafe, with two border crossings:
safe -> unsafe
unsafe -> safe
These crossings cause real headaches. Consider:
struct InnocentType;
impl InnocentType {
fn as_utf8_ptr(&self) -> *const u8 {
todo!()
}
}
fn main() {
let s = "innocent string";
let p1 = s.as_ptr();
unsafe {
// Safe to assume `p1` points to valid UTF-8
}
let t = InnocentType;
let p2 = t.as_utf8_ptr();
unsafe {
// Is it safe to assume `p2` points to valid UTF-8 ???
}
}
The first unsafe block can reasonably assume p1 is valid UTF-8 because str::as_ptr has documented guarantees and it is highly unlikely that the standard lib will be faulty with this simple guarantee. The second cannot: as_utf8_ptr is a name, not a contract.
And that is somewhat analogous to a lot of those discussions about things in Rust not being finally decided, etc. This example shows that the safe <-> unsafe border can create a lot of difficulties, from small ones to larger ones.
The keyword can be misleading and (deliberately or as a lucky accident?) scary, certainly for unsafe blocks.
What it is actually saying is: "I, the coder, take responsibility for ensuring that this code is safe. I am aware that the compiler is technically unable to do this."
As for community concensus on how to write unsafe, there is:
Include a correctly well explained // SAFETY comment (sadly this lint is not warn but allow by default)
Limit unsafe to specific regions of the code
For unsafe fn it's more: "You the coder must take responsibility ..." and the lint for a missing # SAFETY section in the documentation is warn by default.