`PairLike` trait for deref of Tuples? (`&(K, V) -> (&K, &V)`)

I need the following trait for something a bit more complicated (this may be an x-y-problem, but I think this problem itself is interesting enough to try solving it or figuring out why it is not solvable)

As one might know, the compiler can automagically convert references to tuples &(K, V) to (&K, &V).

I created this trait to unpack a "pair-like" tuple:

pub trait PairLike {
    type Left;
    type Right;

    #[must_use]
    fn left(self) -> Self::Left;

    #[must_use]
    fn right(self) -> Self::Right;
}

impl<K, V> PairLike for (K, V) {
    type Left = K;
    type Right = V;

    fn left(self) -> Self::Left {
        self.0
    }

    fn right(self) -> Self::Right {
        self.1
    }
}

this works fine, but I was wondering if it would be possible to implement this:

impl<'a, P: PairLike> PairLike for &'a P {
    type Left = &'a P::Left;
    type Right = &'a P::Right;

    fn left(self) -> Self::Left {
        &(*self).left()
    }

    fn right(self) -> Self::Right {
        &(*self).right()
    }
}

(Spoiler: The compiler is not happy with it)

I think with a bit of unsafe code one might be able to get this working, but I am not sure if this would be safe?

This is obviously working as expected, but relatively limited:

impl<'a, K, V> PairLike for &'a (K, V) {
    type Left = &'a K;
    type Right = &'a V;

    fn left(self) -> Self::Left {
        &self.0
    }

    fn right(self) -> Self::Right {
        &self.1
    }
}

As written, it is not. You are trying to implement the reference projection in terms of the value returned by the left() and right() methods, but functions do not work like that — they do not preserve lvalueness. The return type of a function is a temporary, so if you take the address of a return value, you don't take the (original) address of the field inside the tuple that the function call moved, you are taking the address of a temporary object.

What are you actually trying to do with this? I.e., what is it you want to abstract over?

2 Likes

What are you thinking of here? The closest thing I could imagine was pattern binding, like in a let or match.

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.