Is unsafe Rust worse than C?

Yeah, the very first issue is that there's no top level code execution so you effectively need to start with fn main() {} and introduce it as the "minimum Rust program" and immediately break down a 6 token production and explain what arguments are enough to explain the parens, what the heck "main" means, and now you've explained what a function is, you've just given yourself the job of explaining how there's something else that calls this function, and then when you explain visibility and FFI later you have to justify why main can cheat :grinning_face_with_smiling_eyes:

When you add on any CLI tooling startup, it's a rough start, but I suppose it could definitely be worse.

You could start at a library with tests, but now you instead have to explain at least attributes and the test harness...

That's true for C++, too. Consider C++ ā€œhello, worldā€:

import std;

int main() {

    std::println("Hello World"); 
}

Just how many different things does one need to know to understand how that thing works? And when you go to std::println("x = {}, y = {}", x, y);… does any tutorial describes argument type deduction, compile-time string processing and all that other stuff needed for that line to work?

I actually agree with Jookia to a large extent :slight_smile: but...

C doesn't provide a bunch of useful guarantees that Rust lacks. I've read parts of the C standard pretty closely. It's not clear what it means. It's complicated enough that I would not be able to justify a close reading of it to try and decide whether my C code was valid or not. I don't understand exactly how types get assigned to bytes in standard C, and it matters because of the TBAA rules. I don't know if there's a valid way to write an allocator in standard C. (I think probably not?) The situation in Rust does not seem worse.

I think C, C++, and Rust are actually all in kind of a similar place right now. There are people in all three language communities who are interested in providing guarantees about unsafe code: a real specification, a formal model, verification tools ... good stuff. People are working on it. We are surprisingly far along now. It still feels like victory is 5-10 years away. I really do think we're gonna get there, for memory (pointer operations). If pointers are possible, I think most unsafe compiler intrinsics are a walk in the park; that leaves FFI and inline assembly, and I dunno. It could be a while or it could never happen.

That said, with FFI, I actually usually feel like I'm on solid ground--or rather, I can choose a C API that doesn't push any boundaries, and then I know what to expect. There are rules I need to follow about types, headers, layout... I know a lot of these rules. Some are easy to forget, and they might not all be documented in one place. But if I do absolutely everything right, FFI calls will work. It breaks when I forget stuff or screw up. It's a lot like doing literally anything in C.

FFI is not the place where unsafe Rust feels trickier than C, for me.

Memory safety in unsafe code is the thing. I find it harder to get right in Rust than in C, because in addition to rules, there are pitfalls:

  • using pointers in ways that violate the rules of existing references is UB
  • your unsafe code needs to leave things in a safe state even if something panics
  • or if someone uses mem::forget to skip a destructor

And it's fair to say these concerns don't exist in C. There are no destructors. What's the closest thing to a panic, longjmp? You don't worry about leaving things in a safe state if something calls longjmp.

So in a way, yeah, unsafe Rust might be worse than C, if your goal is to make a computer beep. If your goal is to put a safe wrapper around unsafe primitives, and make a future with fearless beeps :slight_smile: , then what you can do in Rust is just not even on the board as a possibility in C. But it's OK that not everybody wants that.

Except in versions of C where they do exist, right?

Simple return, in the absence of destructors may be just as dangerous.

Depends on whether you actually do use it or not.

But that's the general state of things: it's ā€œeasierā€ to write C code because the rule of the land there is ā€œif it's ever possible to use function safely while following 1000 pages of rules then you are doneā€. While in Rust it's the opposite: ā€œit should be possible to use most functions without reading 1000 pages of rulesā€.

It feels like writing C code is simpler… in reality it's only true if your program is small and you can fit it in your mind. Add 100000 LOC or 1000000 and you wouldn't having real touble, adding linters left and right, destructurs and the whole pile of other tools… and they would still fail.

Yes, but there's the thing: if you want to play by C rules then it's better to do that in C. Using unsafe Rust as some kind of weird C would just make everyone frustrated.

I feel like the issue is calling into external code which may panic. return is a thing to watch for, but at least that's inline in your own function.

Yet kernel developers are adding destructors (or, rather, scopes) to avoid these issues.

And these are not the most careless developers around.

My Computer Engineering curriculum was kind of like that. Math, semiconductor physics, transistors, opamps, logic gates, adders, ALUs, assembly, C, java, application engineering. With some signal processing and control theory somewhere in there.
For schedule reasons it wasn't actually presented in this linear fashion but taught along several concurrent lines instead, but in retrospect I assume that was the underlying idea.

I'm going to mark this as answered on my post. It feels kind of weird to do that but in reality it's been this thread, Discord chats and other nice people that have helped solve my anxiety. So thank you.

The Problem is that we don't have some sort of "save" hardware, imagine a HW Model Influence the Build - that validates all the In-variances against what can actually go into the registers

Then you try to learn something weird like Haskell, Prolog, Forth

I'm glad you mentioned Forth. I learned Forth programming as a teenager using Leo Brodie's amazing "Starting Forth" book. Forth is a wacky language but that book with its humorous and engaging cartoons made all the difference. And it taught me concepts that carried over to other programming languages and environments, like what a stack is and how to efficiently leverage fixed-point arithmetic. I wish there was a book like that for Rust. I acknowledge that Forth is a much smaller, simpler language than Rust, so it's a big ask for sure. But it would awesome to have.

That said, I managed to learn Rust with the resources already available plus friendly people on this forum. Learning Rust is very possible right now for motivated people.

Wow, that's a blast fr0m the past. At the time I was working an a multi-processor, 8 bit, control system in assembler. Wishing we had a high level language to work in.

May be it's a cultural thing but I did not like that book for its silly humour and cartoons. Didn't much like Forth for it's "wackiness" as you put it. But it certainly had lessons in there.

How things have changed.

A little off topic, but if anyone is interested both Starting Forth and Thinking Forth are officially available for free online these days.