Macros 1.1 and derive on traits


#1

During implementation of Macros 1.1 one thing was not ported compairing to compiler plugins: ability to specify derive attribute on traits.

Well, acording to alexcrichton it is actually a bug in derive implementation, but it was very useful for my mockers project and, I think, may be useful for someone else.

I can see following use cases for derive-on-traits:

  • mocking (used by my library)
  • stub/proxy generation for RPC, REST services, etc
  • wrappers generation (which may log each call or wrap it with lock, etc)

It was suggested to revive this ability as unstable feature, my question is: what should I do to ensure this is implemented, maybe create an issue, or write RFC?


#2

I think the “idea” of derive specifically is that it should do nothing but add trait implementations for the type it’s tagged on. That’s a pretty limited subset of the things you actually want to do though, as you’ve noted. I think what we’d do here is not extend derive, but rather support arbitrary procedural macro attributes, so you’d do

#[mock]
trait Foo { ... }

instead of

#[derive(Mock)]
trait Foo { ... }

Unless I’m forgetting something, I think the only real unanswered question here is what do to about hygiene. This doesn’t matter for derive since it’s not introducing any new names, but these kinds of things would. I think we can probably move forward with support for these things without worrying about special hygiene considerations for now though.

cc @nrc


#3

For what it’s worth, during the update from custom_derive 0.1.* to macro-attr 0.2.0, I extended support for derivation attributes to every kind of item, because I couldn’t think of a compelling reason not to. I mean, if someone wants to generate some code based on a trait definition, why not?

Also, I don’t see derive as being intrinsically limited to trait implementations as output. I’ve used it before to implement inherent methods; I think it makes just as much sense to define it as “derive code” as it does as “derive a trait implementation”.


#4

The idea of derive on trait is just about the same: it should do nothing but add this trait implementations.

The only difference is that when you use derive on type, you already have type and name trait you want to be implemented, and when you use derive on trait you already have trait and name which struct implementing it must be generated.

The argument about using procedural macro attribute also may be applied to struct derives: derive isn’t needed at all if macro attributes are allowed.

But derive provides important guarantee (compared to arbitrary macro attribute): item itself can not be modified, so multiple derives can be combined perfectly, and order of applying is not important.

I don’t insist on usage of derive word for this functionality, I’m not native speaker, so maybe it looks strange or something. But some thing for traits with same guaranties as derive must exist, don’t you think so?


#5

I think we should be open to derive adding new named items, in addition to impls, and being attached to any kind of item, not just types. But that seems like a future extension to the feature beyond 1.1.

I think the defining fact about derive is that it doesn’t mutate the item its attached to, but maybe other people do feel like it ought to have a stricter definition.


#6

The built-in #[derive(..)] macros have been there for quite a long time, and they have a specific set of semantics (their order doesn’t matter, they only add a new implementation for that trait, and they only work on specific types). Changing the semantics of #[derive(..)] now seems like a very bad thing to do, as it could just confuse users. Macros 1.1 was also designed to be a small api, so it could be stabilised more quickly.

If stable procedural macros are a desired feature, then maybe their priority should be increased.


Custom derive on traits?
#7

In my view macros 1.1 custom derive is a fairly risky experiment to get as much benefit as possible from as small a subset of procedural macros as possible. In particular, it is only acceptable to me to be on fast path to stabilisation without macro hygiene and other essentials because it has an extremely small surface area. I’m therefore pretty much opposed on principle to any expansion of that surface area, unless there are seriously compelling arguments (like “this breaks Serde for every single users”, as opposed to “I want to write a macro like this, I think it would be useful”).


#8

Now, when macros 1.1 are released, can we continue discussing “derive for traits”?