# Idea: explicit type parameters for derivation

**URL:** <https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375>\
**Category:** language design\
**Created:** [June 8, 2019, 12:06am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375 "2019-06-08T00:06:18Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [June 8, 2019, 12:06am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/1 "2019-06-08T00:06:18Z")

</div>

# Motivation

> <https://github.com/rust-lang/rust/issues/26925>

# Idea

We could add explicit type parameters in the `derive` attribute, indicating which ones ought to be used as constraints in the expanded derivation. These would be equivalent:

```rust
// The derivations require `T: Copy` and `T: Clone` respectively
#[derive(Copy, Clone)]
struct Y<T>(&'static fn(T));

// explicitly constrain `T` the same way
#[derive<T>(Copy, Clone)]
struct Z<T>(&'static fn(T));

```

But with an explicit list, you could choose partial constraints, or even no constraints at all.

```rust
// requires `T: Copy` and `T: Clone`, but `U` is not constrained
#[derive<T>(Copy, Clone)]
struct Partial<T, U>(T, &'static fn(U));

// the derivations are unconstrained
#[derive<>(Copy, Clone)]
struct Free<T>(&'static fn(U));

```

You can also use different constraints for different `derive`s:

```rust
#[derive(PartialEq, Eq)] // implicitly constrained on `T` (status quo)
#[derive<T>(PartialOrd, Ord)] // explicitly constrained on `T`
#[derive<>(Clone)] // unconstrained
struct Foo<T>(Arc<T>);

```

If you need more complicated constraints, there’s still a normal `impl` block…

# Alternatives

After I started writing this, I found @centril’s RFC 2353:

> <https://github.com/rust-lang/rfcs/pull/2353>

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [June 8, 2019, 12:17am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/2 "2019-06-08T00:17:21Z")

</div>

> [@cuviper](#):
>
> After I started writing this, I found @centril’s RFC 2353:

In other words, we can probably ignore this, since that RFC is fully fleshed out. But hey, it's Friday, and I think there's no harm in sharing another idea.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 8, 2019, 12:47am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/3 "2019-06-08T00:47:15Z")

</div>

Interesting; I had not considered this surface syntax as a means of achieving the intended effect. Using `#[derive<T>(...)]` might be more ergonomic overall, which is nice because I’m not entirely satisfied with `#[derive_no_bound(..)]`.

However, I believe the [current attribute grammar](https://github.com/rust-lang/rust/pull/57367) does not support `#[derive<T>(...)]` so we would presumably need to extend it to accept this. cc @petrochenkov

Another aspect to consider is how custom derive macros are going to become aware of the `<T>` here. Currently, I believe they are not told about the `#[derive(...)]` bit.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [June 8, 2019, 1:03am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/4 "2019-06-08T01:03:42Z")

</div>

> [@Centril](#):
>
> Another aspect to consider is how custom derive macros are going to become aware of the `<T>` here.

Maybe there could be a new `#[proc_macro_derive_bikeshed]` to opt in to taking another parameter.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 8, 2019, 1:09am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/5 "2019-06-08T01:09:23Z")

</div>

> [@cuviper](#):
>
> Maybe there could be a new `#[proc_macro_derive_bikeshed]` to opt in to taking another parameter.

We can probably reuse the same attribute `proc_macro_derive` and detect whether there's an additional parameter in the function instead.

Another approach, which might be more useful overall, is to just pass the `#[derive(...)]` stuff to the derive macro itself. That would also allow custom derive macros to do things like "consider the other derived traits" like `#[derive(Copy, Clone)]` does for optimization purposes.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 8, 2019, 1:46am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/6 "2019-06-08T01:46:45Z")

</div>

As a natural extension to the `#[derive<T>(Copy, Clone, ...)]` syntax, it seems to me that you could also allow:

```rust
#[derive<T: Send>(Copy, Clone, ...)]

```

This would simply override all the bounds on `T` to be `where T: Send`.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [June 8, 2019, 2:33pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/7 "2019-06-08T14:33:57Z")

</div>

Could we upgrade derive to a standalone language construct?

```rust
impl derive Copy, Clone for Foo<T> where T: Send;

```

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [June 8, 2019, 3:00pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/8 "2019-06-08T15:00:09Z")

</div>

I feel that instead of extending the syntax of attributes to accept quasi type arguments we could start accepting attribute annotations on type arguments themselves.

---

<div class="post-metadata">

**Author:** ![kennytm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kennytm/32/161_2.png) [@kennytm](https://internals.rust-lang.org/u/kennytm)\
**Post date:** [June 8, 2019, 3:01pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/9 "2019-06-08T15:01:18Z")

</div>

The syntax seems to suggest things like these will be possible. Not sure if these are good things.

```rust
impl<T> derive Clone for Box<MyType<T>>;

impl derive Clone for MyWrapper<OnlyThisVerySpecialType>;
impl derive Clone for MyWrapper<AnotherVerySpecialType>;

```

Also, this syntax can’t work with `proc_macro_derive`. Proc macros don’t have type information.

```rust
impl<X: Serialize + Send> derive Serialize for MyType<X> {}
// ok how `serde` is able to read about fields of `MyType<X>`?
//
// how's the user going to tell serde about `#[serde(rename = "...")]`
// for some fields?

```

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 8, 2019, 3:26pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/10 "2019-06-08T15:26:42Z")

</div>

> [@kornel](#):
>
> Could we upgrade derive to a standalone language construct?
> 
> ```rust
> impl derive Copy, Clone for Foo<T> where T: Send;
> 
> ```

This was discussed in the RFC where you raised the point as well. See [https://github.com/rust-lang/rfcs/pull/2353#issuecomment-385244811](https://github.com/rust-lang/rfcs/pull/2353#issuecomment-385244811) for my thoughts on this. In brief, a mechanism like `impl derive` would be non-macro based invasive change to the compiler because you don't have access to the tokens necessary to tell what the fields of `Foo` are. Given that it would be non-macro based, I don't see how it can interact with custom derive as alluded to by @kennytm.

> [@ekuber](#):
>
> I feel that instead of extending the syntax of attributes to accept quasi type arguments we could start accepting attribute annotations on type arguments themselves.

We already support attributes on type parameters; e.g. `impl<#[may_dangle] T> ...` is valid. [This is what the cited RFC uses](https://github.com/Centril/rfcs/blob/rfc/derive-bound-control/text/0000-derive-bound-control.md#removing-bounds-in-derive-with-derive_no_bound):

```rust
#[derive(Clone)]
struct MyArc<#[derive_no_bound] T>(Arc<T>);

```

I do think that:

```rust
#[derive<T>(Clone)]
struct MyArc<T>(Arc<T>);

```

is both more readable and ergonomic to write.

If you had some other idea, please elaborate. For actual attributes on type _arguments_, this would be syntactically supported by:

> <https://github.com/rust-lang/rfcs/pull/2602>
>
> \### \[🖼️ Rendered\](https://github.com/Centril/rfcs/blob/rfc/attributes-galore/tex…t/0000-attributes-galore.md)
> 
> \### 📝 Summary
> 
> \[proptest\]: https://github.com/altsysrq/proptest
> 
> Permit attributes to be attached to lifetimes, types, bounds, and constraints as well as associated type equality constraints \`Foo\<#\[attr\] Assoc = MyType\>\`. For example, in a hypothetical version of \[proptest\] one may write:
> 
> \`\`\`rust
> \#\[proptest\]
> // #\[quickcheck\] could also work similarly.
> fn addition\_commutes(
> // Run this test for (u8, u8), (u16, u16), and (u32, u32);
> // This is interpreted by \`#\[proptest\]\`.
> (a, b): #\[types(T, u8, u16, u32)\] (T, T)
> ) -\> bool {
> a + b == b + a
> }
> 
> // Accept x: u8 and vec: Vec\<{ y: u8 | y \> x }\>.
> // This is then verified by an external tool.
> fn refined(x: u8, vec: Vec\<#\[require = "\> x"\] u8\>) { ... }
> \`\`\`
> 
> \### 💖 Thanks
> 
> To @petrochenkov and @alexreg for their reviews of the draft proposal.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [June 9, 2019, 7:53am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/11 "2019-06-09T07:53:53Z")

</div>

> [@kornel](#):
>
> Could we upgrade derive to a standalone language construct?

👍

I keep feeling like these more complex attribute things are wanting to be real syntax instead of just a macro. By the time there are expressions or trait bounds or etc in a macro, it seems like all the things that are needed to have that go well (name lookup, autocomplete, etc) aren't worth it.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [June 9, 2019, 3:51pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/12 "2019-06-09T15:51:31Z")

</div>

Oh, no, please, let’s not do that. `Derive`'s beauty is exactly that it’s a macro and as such, custom `derive`s are mostly uniform (at the level of basic mechanism) with the other kinds of macros, and they can also be expanded without additional support from the compiler (all the more, without needing to invent non-parseable dummy syntax in the expanded output).

---

<div class="post-metadata">

**Author:** ![mosh](https://avatars.discourse-cdn.com/v4/letter/m/bc8723/32.png) [@mosh](https://internals.rust-lang.org/u/mosh)\
**Post date:** [June 10, 2019, 1:54pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/13 "2019-06-10T13:54:03Z")

</div>

Simply isn’t this possible?

```rust
derive Copy, Clone for Foo<T> where T: Send;

```

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [June 12, 2019, 8:07am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/14 "2019-06-12T08:07:23Z")

</div>

> [@H2CO3](#):
>
> `Derive` 's beauty is exactly that it’s a macro and as such, custom `derive` s are mostly uniform (at the level of basic mechanism) with the other kinds of macros

They're already invoked differently from other proc macros (`#[derive(foo)]` vs `foo!{}`) and defined differently from other proc macros (`proc_macro_derive` vs `proc_macro`), so I don't see a fundamental problem with potentially changing up either of those.

For example, I could imagine a "by example" version of derive that works for things that are field-by-field, the way so many of the basic derives are, even if one needs full proc derive macros for things like generating stuff from SQL schemas.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [June 13, 2019, 1:23am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/15 "2019-06-13T01:23:04Z")

</div>

@centril, what’s the next step? Are you going to adopt this syntax in your RFC, or should I open a competing RFC with this change?

The other ideas in here of a first-class (non-attribute) derive would surely deserve their own new RFCs, if those folks would like to pursue that.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 13, 2019, 1:46am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/16 "2019-06-13T01:46:42Z")

</div>

> [@cuviper](#):
>
> @centril, what’s the next step?

I was hoping to hear from @petrochenkov re. the feasibility of supporting `#[derive<T>(tts)]` in the attribute grammar.

> [@cuviper](#):
>
> Are you going to adopt this syntax in your RFC

Depending on @petrochenkov's, sure. It would be nice to collaborate on the adjustments needed to the RFC.

However, my existing RFC, changes to it, or a completely new RFC are unlikely to be roadmap goals at the moment for the language team so please don't expect swift action here from us. 🙂

> [@cuviper](#):
>
> The other ideas in here of a first-class (non-attribute) derive would surely deserve their own new RFCs, if those folks would like to pursue that.

Well... given @scottmcm's noted views here, I think perhaps it is a good idea to discuss things some more so that there isn't a core semantic disagreement wrt. macros vs. a special language construct. That is, It would be good if we weren't what appears to be miles apart.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 13, 2019, 2:08am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/17 "2019-06-13T02:08:25Z")

</div>

> [@scottmcm](#):
>
> By the time there are expressions or trait bounds or etc in a macro, it seems like all the things that are needed to have that go well (name lookup, autocomplete, etc) aren’t worth it.

This things already happen and allow users to encode what they need ergonomically. Notably, `serde_derive` allows you to bake bounds into strings (suboptimal, and the language now allows it to be improved). Crates like `snafu` and `failure` also allow expression like things. `proptest_derive` allows you to bake expressions directly into the deriving logic.

Since it already happens, the better question seems to me whether we can/should provide a more common interface that gives a uniform UX across the ecosystem. Making a minor change in terms of compiler complexity by supporting `#[derive<...>(...)]` would do that and would provide a lot of benefits for little complexity.

> [@scottmcm](#):
>
> I keep feeling like these more complex attribute things are wanting to be real syntax instead of just a macro.

How is this going to work practically? _"wanting to be real syntax"_ is perhaps a nice sentiment but it needs to be backed by some mechanism. The way `#[derive(..)]` work right now is completely syntax directed based on the "text" of the thing it is applied to. If you have `impl derive Copy, Clone for Foo<T> where T: Send;` then:

- how will you deal with phase separation issues wrt. not having access to the definition of `Foo` yet?
- how will you support custom traits?

Also, whatever "real syntax" alternative you come up with, it will presumably be complicated for the compiler to implement because its a whole other system to manage concurrently with the macro one. It will also be a whole new system users must learn... What justifies this added complexity as compared to tweaking `#[derive(...)]`? Moreover, why is this "real syntax" more ergonomic than tweaking `#[derive(...)`? It seems to me that something like `impl derive Copy, Clone for Foo<T> where T: Send;` is both more verbose and is also not located with the type definition and so a reader does not get to enjoy the same syntax-directed understanding of the implementation as the compiler would.

> [@scottmcm](#):
>
> For example, I could imagine a “by example” version of derive that works for things that are field-by-field, the way so many of the basic derives are, even if one needs full proc derive macros for things like generating stuff from SQL schemas.

That is a good idea. We have 3 basic forms of macros we are interested in: `bang!(...)`, `#[attribute(...)]`, and `#[derive(...)]`. All 3 of those can be written as procedural macros but only `bang!(...)` macros can be written as `macro_rules!` ones. I see no fundamental reason why `macro_rules!` could not also support `#[derive(...)]` and `#[attribute(...)]` macros.

I think the question of whether we should support custom derive macros based on declarative macros is still missing that both procedural and declarative macros are macros. Declarative ones will, to my knowledge, still have the same phase separation issues as procedural ones.

---

<div class="post-metadata">

**Author:** ![petrochenkov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/petrochenkov/32/2784_2.png) [@petrochenkov](https://internals.rust-lang.org/u/petrochenkov)\
**Post date:** [June 13, 2019, 6:51am UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/18 "2019-06-13T06:51:07Z")

</div>

I’d rather want [https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/coinductive.20all.20the.20way](https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/coinductive.20all.20the.20way) to work out.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [July 11, 2019, 9:05pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/19 "2019-07-11T21:05:07Z")

</div>

But let’s assume for a moment that it does not. Putting aside the desirability of such a change, how feasible do you think it is technically to support e.g.

```rust
Attr = "[" path:Path generics:AttrGenerics? input:AttrInput "]" ;

AttrGenerics = "<" TOKEN_STREAM ">" ;

// As defined today; no change:
AttrInput =
  | {}
  | "(" TOKEN_STREAM ")"
  | "[" TOKEN_STREAM "]"
  | "{" TOKEN_STREAM "}"
  | "=" LITERAL
  ;

```

?

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [July 11, 2019, 11:37pm UTC](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375/20 "2019-07-11T23:37:13Z")

</div>

I definitely think that `[path < args > = value]` is undesirable, so the “generic arguments” should only be available on bracketed forms.

[Next page](https://internals.rust-lang.org/t/idea-explicit-type-parameters-for-derivation/10375.md?page=2)
