Live data from Hacker News

Uninitialized memory: Unsafe Rust is too hard

lucumr.pocoo.org

21–30 of 127 posts

Re: Uninitialized memory: Unsafe Rust is too hard

#21

I am under the impression that even _safe_ Rust is really hard to learn. Several years ago I started with GoLang and it was so easy to start programming even advanced things almost instantly..Rust drives me crazy. The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful.

I suspect you might start to receive a bunch of replies from people with the opposite experience (replies from people who find the syntax easy to read, and the compiler errors clear and understandable). I would like to attempt to preempt that by noting that it's totally reasonable for two people to feel drastically different things about a programming language. Neither view is more correct than the other. That said,…

> That said, I am curious why different people have these different feelings. One aspect is likely rooted in the fact all of our brains are different. But I also wonder if first impressions play a big role here.

Path dependency has big impact on what seems natural, intuitive, etc. Part of that is what you've done before, and part is first impressions, and part of it is your approach to learning (or the approach taking to teaching you) the subject at hand.

I’ve approached Rust via different books and tutorials before and come up with the “it’s awesome, but too hard” feeling and set it aside.

Recently I've been trying Hands-on Rust [0] and going off to the side from it and Rust is clicking pretty well. Not sure if the book is a better fit for me, if the past false starts have prepared the ground, or what specifically changed.

[0] https://pragprog.com/titles/hwrust/hands-on-rust/

Re: Uninitialized memory: Unsafe Rust is too hard

#22

I am under the impression that even _safe_ Rust is really hard to learn. Several years ago I started with GoLang and it was so easy to start programming even advanced things almost instantly..Rust drives me crazy. The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful.

> I am under the impression that even _safe_ Rust is really hard to learn. [...] > The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful. Yes, Rust is hard to learn. Rust does _seem_ over-complicated. However I like to compare Rust to exercise. You need to do a bit of it before you start reaping the benefits of it. If you suspend your judgement for a bit and try to write some Rust,…

That is inspiring. Thanks a lot!

Perhaps the problem was that I was overconfident and immediately started with pretty advanced Rust - writing a web assembly that performs big data analysis using the "polars" library.

Re: Uninitialized memory: Unsafe Rust is too hard

#23
Here's another perspective on why things are the way they are:

One of the central philosophies of Rust is that it should not be possible to execute undefined behavior using only safe code. Rust's underlying core semantics end up being very similar to C's semantics, at least in terms of where undefined behavior can arise, and we can imagine Rust's references as being wrappers around the underlying pointer type that have extra requirements to ensure that they can be safely dereferenced in safe code without ever causing UB.

So consider a simple pointer dereference in C (*p)... how could that cause UB? Well, the obvious ones are that the pointer could be out-of-bounds or pointing to an expired memory location. So references (& and &mut) most point to a live memory location, even in unsafe code. Also pretty obviously, the pointer would be UB were it unaligned, so a Rust reference must be properly aligned.

Another one that should be familiar from the C context is that the memory location must be initialized. So the & reference in Rust means that the memory location must also be initialized... and since &mut implies &, so must &mut. This part is probably genuinely surprising, since it's a rule that doesn't apply to C.

The most surprising rule that applies here as well is that the memory location cannot be a trap representation (to use C's terminology). Yes--C has the same requirement here, but most people probably don't come across a platform that has trap representations in C. The reason why std::mem::uninitialized was deprecated in favor of MaybeUninit was that Rust has a type all of whose representations are trap representation (that's the ! type).

In short, the author is discovering two related issues here. First, the design of Rust is to push all of the burden of undefined behavior into unsafe code blocks, and the downside of that is that most programmers probably aren't sufficiently cognizant of UB rules to do that rule. Rust also pushes the UB of pointers to reference construction, whereas C makes most of its UB happen only on pointer dereference (constructing unaligned pointers being the exception).

The second issue is that Rust's syntax is geared to making safe Rust ergonomic, not unsafe Rust. This means that using the "usual" syntax rules in unsafe Rust blocks is more often than not UB, even when you're trying to avoid the inherent UB construction patterns. Struct projection (given a pointer/reference to a struct, get a pointer/reference to a field) is especially implicated here.

These combine when you deal with uninitialized memory references. This is a reasonably common pattern, but designing an always-safe abstraction for uninitialized memory is challenging. And Rust did screw this up, and the stability guidelines means the bad implementations are baked in for good (see, e.g., std::io::Read).

Re: Uninitialized memory: Unsafe Rust is too hard

#24
post #11

I am under the impression that even _safe_ Rust is really hard to learn. Several years ago I started with GoLang and it was so easy to start programming even advanced things almost instantly..Rust drives me crazy. The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful.

Why was this downvoted? Rust may be the "most loved" language, but after a few weeks with it, I don't love it. We've got to face the reality that it makes simple things way too complicated. In fairness, I have found the compiler errors to be extremely helpful. They often tell me exactly what to fix. But honestly, they shouldn't have to do that. The syntax should have been obvious from the beginning, as it is in most…

Prior exposure to C appears to be negatively correlated with ease in learning Rust. This is why I say Rust is not a language for C programmers -- it's for their replacements. Young programmers with only a few years' experience in JavaScript or Ruby are now coding circles around the old C wizards, contributing bare-metal, bit-banging code that is guaranteed to be free of several classes of bugs those C wizards are still struggling with.

Re: Uninitialized memory: Unsafe Rust is too hard

#25

Earlier quoted context omitted.

> I am under the impression that even _safe_ Rust is really hard to learn. [...] > The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful. Yes, Rust is hard to learn. Rust does _seem_ over-complicated. However I like to compare Rust to exercise. You need to do a bit of it before you start reaping the benefits of it. If you suspend your judgement for a bit and try to write some Rust,…

That is inspiring. Thanks a lot! Perhaps the problem was that I was overconfident and immediately started with pretty advanced Rust - writing a web assembly that performs big data analysis using the "polars" library.

I consider myself reasonably competent in Rust but the webassembly stuff always trips me up, and so do most cross-language tools. You might've just had an unfortunate experience. I'm not sure if I'd pick Rust for WASM unless you already know it, but I suppose it's a good reason to learn the language.

The problem with Rust is that to write good Rust, you need to accept that you can't use the same approach to solve a problem you could use in other languages. The borrow checker and its implications aren't necessarily difficult, but they're different.

I'd compare the experience to someone who started in Python learning Haskell for the first time: it can take weeks or more before one can truly understand a monad. If you start with basic functional programming you can be quite productive before you need such code structures, but when you open a code base where monads are mixed liberally, your head will be spinning.

Rust may be a lot closer to traditional imperative languages, but the implications of the safety mechanisms in the language are something you can't just skip over. It'll take time and practice to write code that the Rust compiler likes.

If you're getting started, I'd recommend writing some toy programs for the CLI instead. I also recommend using "clippy" to warn you of code smells (it'll suggest improvements when it can!) and to get links to specific problems you might not be aware of. As for the IDE, I recommend the rust-analyser plugin over the native "Rust" plugins found in most IDEs, because the basic ones fail to do proper macro expansion and leave you guessing on how to use libraries.

Re: Uninitialized memory: Unsafe Rust is too hard

#26
post #5

In C, when you declare 'struct role r' (not as a static variable), it is not zeroed. The immediate Rust equivalent would be to use std::mem::uninitialized(), not std::mem::zeroed.

But an idiom from C which might inspire some unsafe rust is to memset a struct to zero after declaration in order to guarantee that all fields are initialized before anything would access them.

Is initializing a NonZero field to 0 really initializing it?

Re: Uninitialized memory: Unsafe Rust is too hard

#27

I am under the impression that even _safe_ Rust is really hard to learn. Several years ago I started with GoLang and it was so easy to start programming even advanced things almost instantly..Rust drives me crazy. The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful.

> I am under the impression that even _safe_ Rust is really hard to learn. [...] > The syntax seems overcomplicated, the compiler errors are cryptic, the IDE is not helpful. Yes, Rust is hard to learn. Rust does _seem_ over-complicated. However I like to compare Rust to exercise. You need to do a bit of it before you start reaping the benefits of it. If you suspend your judgement for a bit and try to write some Rust,…

I much prefer Rust over C++, but I find that the problems of C++ have little to do with the language itself.

I've been watching the videos by Andreas King on SerenityOS and the code is so clean that at first I wondered what programming language I was even looking at. I see the SerenityOS codebase as proof that if C++ programmers wanted to write modern, elegant, readable code, they definitely could.

In practice, though, most C++ programs are full of legacy code or are written by people who don't necessarily know about or agree with modern ways to program C++. It's easy to write beautiful code if you also wrote the memory manager and standard library in modern C++, but most people don't have that luxury.

By being created with a more modern standard library, Rust has an advantage over C++. There is no legacy code to remain compatible with and there is no real way to write "old-fashioned" Rust because the project hasn't existed for long enough. I've seen plenty of terrible, ugly Rust, most of it in my own personal projects. The strictness of the language and standard toolset helps, but it's far from a guarantee that enterprise Rust will be readable and clear.

Re: Uninitialized memory: Unsafe Rust is too hard

#28
To the OP - why should creating uninitialized references with static lifetimes be easy? That is a recipe for undefined behavior - borrows aren't pointers, if you want a pointer to be zero initialized, then use a pointer.

If you want safe access to that pointer then wrap it in a struct with an accessor method

Re: Uninitialized memory: Unsafe Rust is too hard

#29
post #8

What is the reason for the rule objects have to be always in a good state even inside unsafe?

One of the core ideas behind unsafe blocks is that they don’t actually change any semantics. All they do is allow more operations. This makes it a lot easier to reason about (for both the programmer and the compiler) since there’s not two different set of rules to remember. It does however makes things a bit clunky since the unsafe bits need to ensure a “safe” state throughout the whole block and not only by the end…

I’ve never understood why they don’t just support partially initialized structs. They’re already doing control flow analysis for initializing variables. It seems like a natural extension to do this for aggregate types (product and sum). From a type theory perspective, a struct T is not a T in unitialized state, it’s. “partial T” that at some point gets transformed into a T. So, you’d not be able to use the T in the normal sense until the compiler can prove that all fields have been init on all possible control flow paths.

Why is this problematic? (I presume there is a fatal flaw as it seems too obvious of a solution..)

Re: Uninitialized memory: Unsafe Rust is too hard

#30

Earlier quoted context omitted.

I suspect you might start to receive a bunch of replies from people with the opposite experience (replies from people who find the syntax easy to read, and the compiler errors clear and understandable). I would like to attempt to preempt that by noting that it's totally reasonable for two people to feel drastically different things about a programming language. Neither view is more correct than the other. That said,…

> That said, I am curious why different people have these different feelings. One aspect is likely rooted in the fact all of our brains are different. But I also wonder if first impressions play a big role here. Path dependency has big impact on what seems natural, intuitive, etc. Part of that is what you've done before, and part is first impressions, and part of it is your approach to learning (or the approach takin…

> Path dependency has big impact on what seems natural, intuitive, etc

So much this. One example I hit a lot is when people keep saying “async/await is too hard, green threads are much more intuitive”: coming from a JavaScript background I feel async/await and all the future combinators much more intuitive than dealing with threads and channels. Before async rust was stabilized I had to learn how to use threads and I was always frustrated how clunky it felt, and now that Rust has async/await I use it for everything IO related, because to me it's just much more familiar.

Post reply on HN