Hacker News new | ask | show | jobs
by andreareina 1598 days ago
I don't know rust, but why isn't the answer, don't try to do what you'd do in C like construct uninitialized structs?
3 comments

They are pretty useful for a number of data structures, and Rust uses them heavily in the standard library.

I'm not aware of as many uses of field by field initialization of a struct but there is an example similar to this blog in the docs[1] (without the alignment considerations.)

That said my read has been the complexity is accidental as a result of language decisions to improve safe rust. MaybeUnit was only defined 3 years ago when it was discovered that mem::uninitialized /zeroed resulted in undefined behavior when used with bools. [2][3]

[1] https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#ini...

[2] https://github.com/rust-lang/rust/issues/53491

[3] https://doc.rust-lang.org/std/mem/fn.uninitialized.html

It's the correct answer.

You still sometimes need it like:

- when highly optimizing some algorithms

- doing FFI

So places you find it include some aync runtimes, some algorithm libraries, the standard library.

Still often times you initialize it by fully writing it, not by writing fields.

Anyway rules are simple:

1. use `ptr::write` instead of `ptr =`

2. use `addr_of_mut!(ptr.x)` instead of `&ptr.x` to get field pointers

3. uhm, `packed` structs are a mess, if you have some you need to take a lot of additional care, this is not limited to rust but also true for C/C++

Also you do not need `#[repr(C)]`, while the rust-specification is pending and as such `repr(Rust)` is pretty much undefined you still can expect fields to be aligned (as else you would have unaligned-`&` which is quite a problem and would likely cause a bunch of breakage through the eco-system).

There may of course be rare cases where having it uninitialized helps, but I would wager that even than the compiler could optimize it more often than not.
It's not that simple.

Like the unused bu allocated space in a Vec is basically a `[MaybeUninit<T>]`.

Or in async runtimes you often have an unsized type with an future trait object inlined (through unsized types anyway need a bit more love ;=) ).

Or some C FFI patterns.

But yes I would say in pure rust the use cases for `MaybeUninit` are rare, and the cases where you need pointers to fields even rarer.

Though while rare in comparison to the amount of code not needing it, still needed enough to be somewhere used (e.g. in a dependency) in many projects even if ignoring std.

Fair enough, I was thinking more along something like making a struct and then iteratively filling out its fields, maybe even through passing a reference to it to another function. After inlining, it should be “uninitalized” in x86 instructions.
Interoperating with C libraries can often force you into this sort of thing.