Comment by smj-edison

2 days ago

I think this crate description encapsulates what's difficult about unsafe rust, which is how unergonomic pointers are. Like why do I need to use `addr_of_mut!`? I'm sure there's a good reason, as Rust tends to think these problems through, but it's very unintuitive compared to returning `&mut`. I feel like I'm juggling way more concepts, which to be fair helps with safety, but it can obscure the algorithm itself.

Does cordyceps have a derive macro? I can imagine that helps a lot with correct implemention, though when it comes to linked lists I can see people wanting to do it themselves.

> Like why do I need to use `addr_of_mut!`?

As of Rust 1.82.0 [0] you no longer need to!

> I'm sure there's a good reason, as Rust tends to think these problems through, but it's very unintuitive compared to returning `&mut`.

The addr_of_mut docs [1] give a pretty decent explanation of its reason for existence; in short, it lets you get a pointer to something without needing to create potentially-invalid intermediate references. It (and &raw) probably aren't going to be needed if all you need is a &mut, though.

> Does cordyceps have a derive macro?

Doesn't appear to from a quick glance, and given what's in the safety section of the docs [2] it'd probably need to be marked unsafe [3]. Unsafe attributes are new to Rust 2024, though, so that might be a bit new.

[0]: https://blog.rust-lang.org/2024/10/17/Rust-1.82.0/#native-sy...

[1]: https://doc.rust-lang.org/std/ptr/macro.addr_of_mut.html

[2]: https://docs.rs/cordyceps/latest/cordyceps/trait.Linked.html...

[3]: https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-att...

  • > > Like why do I need to use `addr_of_mut!`?

    > As of Rust 1.82.0 [0] you no longer need to!

    That's true but misleading. I'm pretty sure the question was why a normal reference is bad. You don't need `addr_of_mut!()`, but you do need `&raw mut`.

    • > I'm pretty sure the question was why a normal reference is bad.

      Oh, completely missed that interpretation. I think in that case it comes down to references being incompatible with the desired semantics for an intrusive list - & doesn't work if you want to modify what you're pointing to, and &mut doesn't work since you may want multiple things to be able to point to and modify whatever you're pointing to.

  • So how do I take a shared reference to a variable named "raw"?

    Complicating the grammar for no good reason. This should have stayed a macro.

  • Interesting. I stopped working with Rust about two years ago, so it looks like there's been a lot more polish in these areas.

> what's difficult about unsafe rust, which is how unergonomic pointers are. Like why do I need to use `addr_of_mut!`?

Things are slowly getting better here! '&raw'/'&raw mut' reference operators were stabilized a couple years ago.

Another ergonomic improvement in the pipeline is a better way to access fields behind pointers, something like C's -> operator. This is taking some time to design because there are things other than raw pointers that would benefit from a generalized field projection mechanism, like Pin, NonNull, and (potentially user-defined) smart pointer types.

> Like why do I need to use `addr_of_mut!`? I'm sure there's a good reason, as Rust tends to think these problems through, but it's very unintuitive compared to returning `&mut`.

That documentation appears to be out of date. The `addr_of_mut` macro was elevated to a first-class language feature, `&raw mut` (there's also a corresponding `&raw` operator). These two operators differ from the usual `&mut` and `&` in that they create raw pointers rather than references; prior to the introduction of this feature (or the aforementioned macros that served as precursors) to create a raw pointer you might need to have done a cast like `&foo as *const` in order to create a raw pointer by casting from a reference, but this could have safety consequences if the temporary reference was to an invalid object. Therefore `&raw` and `&raw mut` were introduced to create raw pointers directly without introducing an intermediate reference, which was arguably the most subtle footgun in unsafe Rust for a few years, and it's nice that it's now addressed.