Implicitly implement Deref for types of another trait

Assume there's a trait called StringableValue; its purpose is to be implemented for types that hold values that also have string representations:

pub trait StringableValue {
  type Value;

  fn set(&mut self, sval: &str) -> Result<(), Error>;
  fn val(&self) -> &Self::Value;
  fn sval(&self) -> &str;
}

Now let's say that one would want Deref[*] to be implemented for all StringableValue implementors and it should return a reference to StringableValue::Value.

A requirement can be expressed:

pub trait StringableValue : Deref {
  // ...
}

However, is it possible to actually express the implementation a single time, using generics?

Something along the line of:

impl<T> Deref for T
where
  T: StringableValue
{
  type Target = <T as StringableValue>::Value;
  fn deref(&self) -> &<T as StringableValue>::Value {
    self.val()
  }
}

[*] Don't worry, I know it's a bad idea to implement Deref on things that aren't smart pointers. This is just about pure curiosity, and not anything that will be used in practice.

The orphan rules won't permit you to define a generic impl<T> ::std::ops::Deref for T, because Deref is a foreign trait. With your own Deref trait we can get the default implementation to work though:

pub trait StringableValue: Deref<Target = Self::Value> {
    type Value: ?Sized;

    fn set(&mut self, sval: &str) -> Result<(), Error>;
    fn val(&self) -> &Self::Value;
    fn sval(&self) -> &str;
}

pub trait Deref {
    type Target: ?Sized;

    fn deref(&self) -> &Self::Target;
}

impl<T> Deref for T
where
    T: StringableValue,
{
    type Target = <T as StringableValue>::Value;

    fn deref(&self) -> &<T as StringableValue>::Value {
        self.val()
    }
}

Playground.

3 Likes

Minor note: The compiler now allows T::Value to be used in these cases.

2 Likes

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.