oneshot icon indicating copy to clipboard operation
oneshot copied to clipboard

Sender could be contravariant if desired

Open orlp opened this issue 7 months ago • 2 comments

The Sender struct has the following comment:

pub struct Sender<T> {
    channel_ptr: NonNull<Channel<T>>,
    // In reality we want contravariance, however we can't obtain that.
    //
    // Consider the following scenario:
    // ```
    // let (mut tx, rx) = channel::<&'short u8>();
    // let (tx2, rx2) = channel::<&'long u8>();
    //
    // tx = tx2;
    //
    // // Pretend short_ref is some &'short u8
    // tx.send(short_ref).unwrap();
    // let long_ref = rx2.recv().unwrap();
    // ```
    //
    // If this type were covariant then we could safely extend lifetimes, which is not okay.
    // Hence, we enforce invariance.
    _invariant: PhantomData<fn(T) -> T>,
}

However it's actually possible to make a contravariant NonNull pointer:

struct ContravariantNonNull<T> {
    ptr: NonNull<()>,
    _marker: PhantomData<fn(T) -> ()>,
}

impl ContravariantNonNull<T> {
    #[inline(always)]
    fn as_ptr(&self) -> *mut T {
        self.ptr.as_ptr().cast()
    }
}

orlp avatar Jul 13 '25 09:07 orlp

Interesting. I'll look into this when I have the time. Do you know if this actually unlocks any use case or improves the ergonomic in any practical way?

faern avatar Jul 13 '25 18:07 faern

No, nothing comes to mind.

orlp avatar Jul 13 '25 18:07 orlp