Assuming I have a struct Orange(*mut u8)
the *mut
makes it invariant with respect to u8
, is there any way this type would behave differently than struct Apple(*const u8)
.
No, there must be a lifetime for you to observe it.
Looking for an answer I dug up this 0738-variance - The Rust RFC Book here it says:
However, in practice,
*mut
pointers are often used to build safe abstractions, the APIs of which do not in fact permit aliased mutation. Examples areVec
,Rc
,HashMap
, and so forth. In all of these cases, the correct variance is covariant -- but because of the conservative treatment of*mut
, all of these types are being inferred to an invariant result.
What do they mean, where would lifetimes for these cases come from?
Well for example a Vec<&'a str>
would have a lifetime on the raw pointer.
Using *mut u8
inside Vec
would then mean we can't widen or narrow the 'a even though that would be safe?
Well, it would be an *mut &'a str
in that case, but yes. Using a mutable raw pointer would disallow narrowing the lifetime.
If you had a *mut &'a str
, the &'a str
would be invariant so the 'a
couldn't change.
u8
is also invariant behind a *mut
, but it has no lifetime, so it doesn't matter -- you cant' observe it.
Note that the RFC is from 2014. Vec
is implemented with Unique
now. That part of the RFC was basically "if we adapt this model, how do we best soundly adjust current practices?"
Sure, but Unique
is defined like this:
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
pub struct Unique<T: ?Sized> {
pointer: *const T,
// NOTE: this marker has no consequences for variance, but is necessary
// for dropck to understand that we logically own a `T`.
//
// For details, see:
// https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
_marker: PhantomData<T>,
}
The variance rules are real and in use in Rust today.
Right, from the RFC:
The complete solution to this seems to have two parts. First, for convenience and abstraction, we should not be building safe abstractions on raw
*mut
pointers anyway. We should have several convenient newtypes in the standard library, likeptr::Unique
, that can be used, which would also help for handling OIBIT conditions andNonZero
optimizations. In my branch I have used the existing (but unstable) typeptr::Unique
for the primary role, which is kind of an "unsafe box".Unique
should ensure that it is covariant with respect to its argument.However, this raises the question of how to implement
Unique
under the hood, and what to do with*mut T
in general. There are various options:
[...]
- Rewrite safe abstractions to use
*const
(or evenusize
) instead of*mut
, casting to*mut
only they have a&mut self
method. This is probably the most conservative option.
Variance is a property of "type constructors". It tells us something about: "How does Type<T> react when T changes?". I.e variance is something we bring up when talking about that Type<_> as a general thing.
Since we don't have any type constructor here, no type (or lifetime) parameters, the invariance concept doesn't apply at all .
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.