Implementing Debug for traits

I just started exploring how traits work, here is a code snippet:

use core::{fmt,fmt::Debug,fmt::Formatter};

/// Compiled expression which yields type T when evaluated.
pub trait CExp<T> 
{
  fn eval( &self, e: &mut EvalEnv ) -> T;
  fn format( &self, f: &mut Formatter ) -> fmt::Result;
}

impl <T> Debug for dyn CExp<T>
{
  fn fmt(&self, f: &mut Formatter) -> fmt::Result 
  {
    self.format( f )
  }
}

#[derive(Debug)]
pub struct Add<T>
{
  left: Box<dyn CExp<T>>,
  right: Box<dyn CExp<T>>
}

impl <T> CExp<T> for Add<T> where T: std::ops::Add<Output = T> + Debug
{
  fn eval( &self, e: &mut EvalEnv ) -> T
  {
    self.left.eval( e ) + self.right.eval( e )
  }
  fn format( &self, f: &mut Formatter ) -> core::fmt::Result
  {
    self.fmt( f )
  }
}

This works, and I can Debug print everything. Every struct I make which implements CExp has the same code for format. This is quite ok, but is there a trick to avoid repeating the "redundant" code for format over and over again?

If you add Debug as a required trait (“supertrait”) for CExp<T>, then the compiler will automatically implement Debug for dyn CExp<T>:

pub trait CExp<T>: Debug
{
  fn eval( &self, e: &mut EvalEnv ) -> T;
}

(Playground)

5 Likes