Impl Deref<U1> for T AND impl Deref<U2> for T

Double-implementing Deref apparently can't be done. Suppose I have this structure:

struct DerefExample<T, U> {
    value: T,
    value2: U
}

And, I want deref to target BOTH T and U. Is there a way to do this? The naive method does not work due to "conflicting implementations":

// target T
impl<T, U> Deref for DerefExample<T, U> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

// target U
impl<T, U> Deref for DerefExample<T, U> {
    type Target = U;

    fn deref(&self) -> &Self::Target {
        &self.value2
    }
}

It's not actually important to get this working, I'm just curious to see if the idea of a multi-target Deref has already manifested in rust

This is forbidden, since deref_example.deref() must be unambiguous. Deref isn't special here, it's just another trait. Could you show how this is supposed to be used?

Yes, it would be ambiguous to the compiler.

well, I was thinking about wrapping an Arc around a structure T that holds U1 and U2, and, wanted to be able to access the methods of U1 and U2 from the context of T (without typing t.u1.my_function() nor t.u2.my_other_function()).

In the multi-deref case, I would only need to type:
t.my_function() or t.my_other_function(), and was hoping the compiler would automatically figure out which one was which, so long as there weren't overlapping method names.

It seems one way to get this to work is through macros ... a #[MultiDeref(U1=u1, U2=u2)] attribute that goes ontop of a struct where u1 is the field name with type U1, and u2 is the field name for type U2. Then, the macro could throw a compile-time error if it detected overlapping function names

This seems to be impossible for another reason: there's no way macro will know the available methods on the types. Don't forget that macros work on the syntactic level, before any type resolution.

1 Like

Implement Borrow(Mut) and/or AsRef/Mut, instead.

4 Likes

I'm not sure if Borrow can be correctly implemented here. According to the docs:

In particular Eq , Ord and Hash must be equivalent for borrowed and owned values: x.borrow() == y.borrow() should give the same result as x == y .

But this constraint is violated for Borrow<U> when you have two structs with the same U and different Ts.

This is the first-way that jumped out to me, but was more curious to see if it could be done with merely Deref/Mut

It is true that you have to be careful with Eq, Ord, and Hash if you implement Borrow, however, you don't have to implement any of them. So it's possible to implement none of those traits, and still implement both Borrow<U> and Borrow<V> for T even though U and V don't hash/compare the same.

Of course, then you can't use any APIs that use Eq, Ord or Hash. So the only benefit Borrow<T> gives you over AsRef<T> is that it's automatically implemented for T, &T and &mut T.

1 Like

There is no indicator of an issue with Borrow(Mut) for the given example. As long as you don't implement Eq, Ord, Hash for the struct you implement Borrow(Mut) for, there can't possibly be a conflict about those traits.

In that case the documentation is unclear, because "Does not compile" is a very different result from "compiles, and produces a bool". I.e. I took that language to specify that either both the borrowed and owned types should implement Eq or neither.

1 Like

You are not implementing Deref<U1> and Deref<U2>. You're implementing Deref and Deref, but traits can only be implemented once.

1 Like