4 ms·
A minor rant about std::ptr::NonNull: this wraps a *mut T, and there is no equivalent for *const T. So if you want to use the optimization for a pointer-to-cons
by ridiculous_fish 4y ago
A minor rant about std::ptr::NonNull: this wraps a *mut T, and there is no equivalent for *const T. So if you want to use the optimization for a pointer-to-const, you must cast away constness, and just be careful to never mutate the pointee. In practice that's exactly what the standard library does.
- Rusky 4y agoThere's a bit of a sentiment that the `*mut T`/`*const T` distinction is more unhelpful noise than an actually useful feature. They can be freely cast between each other - `*mut T` to an immutable object is totally legal - and thus (much like C and C++'s const) don't really mean anything about the thing they point to. Further, writing through one or converting back to a reference is already `unsafe`, so even using them as a lint doesn't add much. AIUI that is why NonNull only has one variant- it's just easier to have one kind of pointer. But interestingly, even though `NonNull`'s API is written in terms of `*mut T`, it is implemented in terms of `*const T`: https://github.com/rust-lang/rust/blob/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/core/src/ptr/non_null.rs#L52 https://github.com/rust-lang/rust/blob/4ca19e09d302a4cbde14f.... This makes it covariant (`NonNull<T>` for `T: 'long` is a subtype of `NonNull<T>` for `T: 'short`), while `*mut T` is invariant, since this is the more common mode, and also the more flexible option that can be restricted back down to invariance when necessary. So NonNull is sort of a re-setting of the defaults: the unsafe mutability of `*mut T` (since people wind up needing to cast covariant `*const T`s to `*mut T` to write through them a lot anyway), with the covariance of `*const T`.