Is it fine to use Deref/DerefMut to obtain extra blanket trait impls?

With traits that are meant to be used as trait bounds, it can often be nice to add blanket impls for &T, &mut T, Rc<T>, Arc<T>, Box<T>.

This is an example from the futures library. They seem to use a number of things like macros to make this more convenient, as well as Pin impls that use Deref.

I was wondering if there are any gotcha's from just using this instead of spelling out all of the wrapper types:


pub trait Assoc 
{
    fn assoc( &self );
}

impl<A, T> Assoc for T
where
    A: Assoc,
    T: std::ops::Deref<Target=A>
{
    fn assoc( &self ) { (**self).assoc() }
}

The same question goes for DerefMut.

This can cause problems if you ever want to make additional blanket impls. Rust has no concept of traits being disjoint from each other, so a blanket impl for T: Deref will conflict with a blanket impl for T: SomethingElse.

It could potentially conflict with specific impls as well. If you try to impl Assoc for ForeignStruct, you'll get a conflict because the crate that defines ForeignStruct might add an implementation of Deref in the future.

2 Likes

Ah, makes sense. Thanks for clarifying. And I'm glad I asked before rolling it out.