-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: Make Lazy<T, F>
covariant in F
#167
Comments
If this is something you'd consider, let me know. I can give it a shot. |
I think we should have it. I don't particularly mind unsafe, as long as it is sound. One problem here is that it'll be hard to check soundness for me. I guess, let's do the following:
|
We also should fix https://doc.rust-lang.org/std/lazy/struct.Lazy.html in the same way -- for std types, it's very important that they are pedantically correct in terms of variance and such. |
For what is worth, since the api w.r.t. |
Drive by comment: I've hit a similar issue, for which I could not find a fully satisfactory answer because it seems impossible to get interior mutability and covariance at the same time for owned data.
I fully agree. Even |
I think it makes sense that I did come up with a hack that sort of allows for covariant My idea was to create a #[repr(C)]
union CovUnsafeCell<T, const T_SIZE: usize> {
value: ManuallyDrop<T>,
cell: ManuallyDrop<UnsafeCell<[u8; T_SIZE]>>
}
impl<T, const T_SIZE: usize> CovUnsafeCell<T, T_SIZE> {
pub fn new(t: T) -> Self {
// T_SIZE is the number of bytes within the UnsafeCell.
// It has to be >= size_of::<T>() so that a raw mut pointer from the UnsafeCell
// has permission to modify all of the value field.
assert!(T_SIZE >= size_of::<T>());
CovUnsafeCell { value: ManuallyDrop::new(t) }
}
// Safety: Using this pointer has all the requirements of UnsafeCell and
// an extra requirement that mutations should not cause violations in covariance.
pub fn get(&self) -> *mut T {
unsafe { &self.cell }.get() as *mut T
}
} This is covariant since the |
@douglas-raillard-arm a potential trick to make it not need a #[repr(C)]
union CovariantCell<T> {
value: ManuallyDrop<T>,
_mutable: ManuallyDrop<Cell<u8>>,
}
Footnotes |
Another alternative, for the specific case of
Worst case scenario we'll have to pay for a separate |
233: Make `unsync::Lazy<T, F>` covariant in `F` r=matklad a=danielhenrymantilla "Continuation" from #230, which partially handles #167. - Incidentally, this also makes `unsync::Lazy` smaller in size in most cases, since `T` and `F` are now sharing the same `union` storage. The `sync` can basically use the same logic (my PR paves the way for such a follow-up PR), only the whole thing would need to be moved to each of the possible `imp`lementations of `sync::OnceCell`, and special care to synchronization semantics will be in order, which I prefer to let somebody else do. Co-authored-by: Daniel Henry-Mantilla <[email protected]>
I ended up circling back to the same issue and I realized that a covariant
Maybe it would be possible to design a |
I have some code where we'd like to use
Lazy
values as fields of structs, which means boxing closures:The problem is that this type alias is invariant in
'a
, becauseLazy<T, F>
is invariant inF
. So actually using this type causes insurmountable lifetime issues in our code.I hesitate to ask for this, because the only way to get it is to lie a lot to Rust about what's inside the
Cell
. The API would be safe, but I don't see a way to do it without a fairly gross amount of unsafe code.The text was updated successfully, but these errors were encountered: