Custom derive on traits?


#1

Hi -

I’d like to be able to implement custom derive for traits. For example:

#[derive(BoxTrait)]
pub trait Foo {
  fn foo(&self) -> i32;
  fn bar(&self) -> String;
}

would automate generating something like:

impl Foo for Box<Foo> {
  fn foo(&self) -> i32 { self.as_ref().foo() }
  fn bar(&self) -> String { self.as_ref().bar() }
}

to allow Box<Foo> to be used anywhere Foo is required.

Another more complex (but related) example would be BoxableTrait, which would generate a function which can take an implementation of an object-safe trait Foo and produce a boxed trait object Box<Foo>s. (More generally it would be nice if it could also take trait-constrained type parameters and associated types and normalize them into boxed trait objects as well, to make the types as uniform as possible - but I’m not sure what it would take to do that mechanically in general.)

From what I can tell, this isn’t currently possible - custom derive only works for struct and enum. Are there any proposals to generalize it to trait as well? Or would that already work in unstable?

Are there any fundamental problems I’m overlooking that would doom this idea from the start?

Thanks!


#2

I don’t know if extending the custom derive for traits is planned, but you can achieve similar thing with regular macros: here’s a proof of concept implementation.


#3

Oh, nice! That’s an interesting starting point - next step is to see if it can be extended to handle associated types (with constraints, etc) too:

pub trait Foo {
    type MyType;
    type FutureThing: Future<Item=Self::MyType> + Send + 'static;
    fn foo(&self) -> i32;
    fn bar(&self, x: i32) -> String;
}

impl<MT, FT>
    Foo<MyType=MT, FutureThing=FT>
    for Box<Foo<MyType=MT, FutureThing=FT>>
    where FT: Future<Item=MT> + Send + 'static,
{
    type MyType=MT;
    type FutureThing=FT;
//...
}

It’s traits with associated types which really prompted this, because of all the additional overhead they bring (the methods are simple by comparison).


#4

Oh, I imagined you want to box the associated types (at least some of them), I mean

type FutureThing = Box<Future<Item=Self::MyType> + Send + 'static>;

Your variant seems easier, as you won’t need to convert anything. I think the macro could be extended to cover associated types, provided you’ll pass the names for generics in some kind of list.


#5

I was wondering if the assoc type names could be used as the generic names.


#6

I asked for the same feature when macros 1.1 were announced.