{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreiatpbw3qzfwfcqzlgridhycwabh7jmxlf26tz2mwzb6xw7nm7cxe4",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mhwozoavurm2"
  },
  "path": "/t/brainstorming-syntax-for-const-derive/24110#post_1",
  "publishedAt": "2026-03-25T23:38:06.000Z",
  "site": "https://internals.rust-lang.org",
  "tags": [
    "derive-aliases",
    "Provide a way for derives to know if they were invoked with `#[derive_const]` · Issue #118304 · rust-lang/rust · GitHub"
  ],
  "textContent": "I made a library derive-aliases which extends the `derive` macro's syntax with `..Alias` that expands into user-defined aliases:\n\n\n    #[derive(Debug, ..Ord, ..Copy)]\n    struct User;\n\n\nUsers define their own aliases:\n\n\n    // Define the aliases\n    derive_aliases::define! {\n        Eq = ::core::cmp::PartialEq, ::core::cmp::Eq;\n        Ord = ..Eq, ::core::cmp::PartialOrd, ::core::cmp::Ord;\n        Copy = ::core::marker::Copy, ::core::clone::Clone;\n    }\n\n\nI'm now preparing a v0.5 release, and one of the features it will support is **const-deriving traits**.\n\nCurrently, we have a separate macro for const-deriving traits: `#[derive_const]`:\n\n\n    #[derive_const(Debug, Ord, Copy)]\n    struct User;\n\n\nThis has a few usability issues in my mind:\n\n  * It is a distinct attribute from `derive`.\n  * If you want to const-derive 1 of 8 traits that are being derived, you have to delete the trait in the middle, and add a new attribute\n\n\n\nconst-deriving traits should be as easy as adding a `const` annotation next to the trait, directly inside of the `derive` macro.\n\nIn my crate I will support the following syntax for const-deriving:\n\n\n    // Define the aliases\n    derive_aliases::define! {\n        Eq = const ::core::cmp::PartialEq, const ::core::cmp::Eq;\n        Ord = ..Eq, ::core::cmp::PartialOrd, ::core::cmp::Ord;\n        Copy = ::core::marker::Copy, ::core::clone::Clone;\n    }\n\n    #[derive(const Debug, ..Ord, ..Copy)]\n    struct User;\n\n\nExperimenting stuff like that is great in external crates before it can be considered for inclusion in the language.\n\nAnd the `derive-aliases` crate is the only one that supports this, likely because (as I later found out) it is _extremely_ hard to create a custom `derive` that works as you expect. (due to derive helper attributes working with name resolution in a context where we only have access to tokens)\n\n# Syntax for const-deriving traits\n\nI've seen several suggestions on this.\n\nThe one that first comes to mind:\n\n\n    #[derive(const PartialEq)]\n\n\nI've also seen this syntax:\n\n\n    #[derive(PartialEq(const))]\n\n\nWith the idea that a derive macro could hypothetically accept an arbitrary tokenstream, much like an attribute macro:\n\n\n    #[derive(PartialEq, Serialize(const, skip_serializing_none, tag = \"...\"), Deserialize(const, deny_unknown_fields, Debug)]\n\n\nI am against that idea because this will make it extremely difficult to understand the traits that are being defined, since it won't all be in a single place - there will be a bunch of syntactic noise interspersed with all the derives. It _will_ be abused\n\nI think that the helper attributes that we currently have are perfectly fine:\n\n\n    #[derive(PartialEq, Serialize, Deserialize)]\n    #[serde(deny_unknown_fields)\n\n\nOn that topic of helper attributes, what about if the derive macro just used those?\n\n\n    #[derive(PartialEq, Debug, Eq, Copy, Clone, Ord, PartialOrd)]\n    #[partial_eq(const)]\n    #[debug(const)]\n    #[clone(const)]\n    // ...\n\n\nThat's a lot of syntax noise!\n\nThis is also impossible to add to the language without breaking backwards compatibility, because adding a new `partial_eq` helper attribute to the `PartialEq` derive will conflict with `BetterPartialEq`'s `partial_eq` attribute\n\nWe should also have a common interface for const-deriving traits. We dont want to hope that a convention will arise, because it might not. We dont want inconsistency for a fundamental language feature:\n\n\n    #[derive(PartialEq, Debug, Eq, Copy, Clone, Ord, PartialOrd)]\n    #[partial_eq(impl_const)]\n    #[debug(const)]\n    #[clone(const = true)]\n    // ...\n\n\nThe `const` keyword should ideally be as close to the derive as possible.\n\n`derive(Clone(const))` without allowing extra syntax in those parentheses might be OK, but it will look very out of place with the rest of the language, and `derive` plus `const` are both cote language features, so they should work as you expect.\n\nSo I think the best syntax for const-deriving traits is:\n\n\n    #[derive(const PartialEq)]\n\n\n# How macros know if they are being const-derived\n\nMacros need to somehow find out if they are being const-derived.\n\nOne proposal I've seen suggested is that the derive macro can take a 2nd argument:\n\n\n    #[proc_macro_derive(Serialize, attributes(serde)]\n    fn Serialize(input: TokenStream, metadata: Metadata) -> TokenStream\n\n\nThis `metadata` object can be opaque and have an `fn is_const(self) -> Option<Span>` function. We can add more information to this object if we want to in the future.\n\nNotably I think this function should return `Option<Span>` so that in case a derive macro doesnt support being const-derive, it can create a helpful error message pointing at the `const` keyword itself.\n\n# Should const-derive be the default?\n\n`const` is not the default anywhere in the language, so in my opinion it would be inconsistent for that to be here.\n\nThat is, a trait should always be implemented by a derive macro without `const`, and only be `const`-implemented if the `const` keyword is used\n\n> Is it ok for a proc macro to give a `const` impl when called with `#[derive]`\n\nNote that it's unlikely that a derive macro can _always_ be implemented as const, since usually bounds are added on the item's fields.\n\nFor marker traits like `Copy`, I'm torn..On one hand, it can always be implemented as `const` so the `const` keyword would be noise you have to add literally everywhere. On another hand, it would be inconsistent to implement something in `const` without requiring the `const` keyword.\n\nPerhaps we can be okay with that, and it could increase the incentive of having something like derive-aliases built-in to the language.\n\n# Links\n\n  * Provide a way for derives to know if they were invoked with `#[derive_const]` · Issue #118304 · rust-lang/rust · GitHub\n\n",
  "title": "Brainstorming syntax for const derive"
}