# \#\[cmp(ignore)\] attribute for deriving \`\*Eq\`, \`\*Ord\`, \`Hash\`

**URL:** <https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087>\
**Category:** language design\
**Created:** [July 26, 2022, 8:43am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087 "2022-07-26T08:43:28Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![JoJoJet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jojojet/32/9655_2.png) [@JoJoJet](https://internals.rust-lang.org/u/JoJoJet)\
**Post date:** [July 26, 2022, 8:43am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/1 "2022-07-26T08:43:28Z")

</div>

In the same vein as allowing a #[default] attribute on enum variants, adding a #[cmp(ignore)] attribute to a field should tell the derive macros for `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash` to ignore that field.

Apologies if this has been posted before, I can't think of many good search terms for this.

---

<div class="post-metadata">

**Author:** ![mbartlett](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbartlett/32/8691_2.png) [@mbartlett](https://internals.rust-lang.org/u/mbartlett)\
**Post date:** [July 26, 2022, 8:50am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/2 "2022-07-26T08:50:43Z")

</div>

With deriving PartialEq and Eq, should it also ignore it for structural matching?

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [July 26, 2022, 1:20pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/4 "2022-07-26T13:20:58Z")

</div>

> [@JoJoJet](#):
>
> adding a #[cmp(ignore)] attribute to a field should tell the derive macros for `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash` to ignore that field.

Hmm. Why should a `cmp` attribute influence the `Hash` impl? My gut feels like it wants a different attribute to say "does not contribute to hashing" (say, an internal cache or something).

---

<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:** [July 26, 2022, 2:29pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/5 "2022-07-26T14:29:36Z")

</div>

There is a relationship that hashes must be equal when the values compare equal. So if a field is ignored for equality, it should also be ignored for hashing.

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [July 26, 2022, 2:33pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/6 "2022-07-26T14:33:51Z")

</div>

Ah, fair enough.

---

<div class="post-metadata">

**Author:** ![rkuhn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rkuhn/32/6659_2.png) [@rkuhn](https://internals.rust-lang.org/u/rkuhn)\
**Post date:** [July 27, 2022, 7:44am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/7 "2022-07-27T07:44:43Z")

</div>

A very similar request could be made for `#[debug(ignore)]` and even `#[clone(ignore)]` (i.e. use the `Default::default()` instead of cloning the field). I’ve written quite a few such manual implementations just because a field needed to be ignored.

There is a balance to be struck between complicating the mechanism by making it more customisable and the gain in consistency (this only applies to `#[cmp(ignore)]`) and readability won by removing the clutter that needs a human brain diff to figure out “oh, this impl exists only to ignore that field — ah, and it is actually correctly done”.

To my mind the benefits outweigh the cost, but I can see how others may come to a different conclusion.

---

<div class="post-metadata">

**Author:** ![rkuhn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rkuhn/32/6659_2.png) [@rkuhn](https://internals.rust-lang.org/u/rkuhn)\
**Post date:** [July 27, 2022, 7:50am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/8 "2022-07-27T07:50:49Z")

</div>

Pattern matching is fixed by the language, not customisable via traits, so I’d find it highly surprising to see a `derive` macro attribute effecting `match` behaviour.

Another consideration is that the desire to extract a field’s value is not bound to whether this field semantically is part of its container’s identity.

---

<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 27, 2022, 8:09am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/9 "2022-07-27T08:09:25Z")

</div>

That's not quite right 🙂

`StructuralEq` refers to the ability to write

```rust
#[derive(PartialEq, Eq)]
struct Thingy(i32, i32);

const THINGY: Thingy = Thingy(0, 1);

let thingy = Thingy(1, 2);

match thingy {
    THINGY => println!("equals the constant"),
    _ => println!("doesn't equal the constant"),
}

```

Using a constant like this is only valid if the type derives `PartialEq`, as does all of its fields' types. This is represented in the compiler as a `StructuralEq` trait, of which an implementation is provided by the derive.

`StructuralEq` is not provided for custom `PartialEq` implementations. I'd very much expect a derived `PartialEq` to not provide `StructuralEq` either.

---

<div class="post-metadata">

**Author:** ![rkuhn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rkuhn/32/6659_2.png) [@rkuhn](https://internals.rust-lang.org/u/rkuhn)\
**Post date:** [July 27, 2022, 8:37am UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/10 "2022-07-27T08:37:34Z")

</div>

Oh, I learnt a new feature today, thanks! I had misunderstood “structural matching” to refer to normal deconstruction (to which my points still apply).

I’m not sure if I agree with not providing `StructuralEq` and `StructuralPartialEq` if some fields are ignored, if that is what you’re saying: why should `x == CONST` behave differently from `match x { CONST => true, _ => false }`?

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [July 27, 2022, 1:15pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/11 "2022-07-27T13:15:01Z")

</div>

EDIT: this is incorrect, see comment below ([#[cmp(ignore)] attribute for deriving `*Eq`, `*Ord`, `Hash` - #12 by Nemo157](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/12))

```rust
#[derive(PartialEq, Eq)]
struct Thingy(#[cmp(ignore)] i32, i32);

let thingy = Thingy(1, 2);

match thingy {
    // Should the following match succeed?
    Thingy(99999999, 2) => println!("matches!"),
    _ => println!("doesn't match"),
}

```

If matching behaves differently from `Eq`, then that's a potential footgun. But if a pattern that doesn't look like it matches the scrutinee actually does match because of details of the `Eq` impl, that's also potentially a footgun. Rust currently deals with this by not allowing types with custom `Eq` impls to do structural match at all.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [July 27, 2022, 3:54pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/12 "2022-07-27T15:54:53Z")

</div>

That specific case isn't using `StructuralEq`, it's a tuple-struct pattern so it will definitely not match. For `StructuralEq` you would need to test:

```rust
const THINGY: Thingy = Thingy(999999999, 2);
match thingy {
    // Should the following match succeed?
    THINGY => println!("matches!"),
    _ => println!("doesn't match"),
}

```

(And introducing inconsistencies between struct patterns and `const` path patterns is another problem).

---

<div class="post-metadata">

**Author:** ![tema2](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tema2/32/6498_2.png) [@tema2](https://internals.rust-lang.org/u/tema2)\
**Post date:** [July 27, 2022, 4:11pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/13 "2022-07-27T16:11:27Z")

</div>

maybe just an attribute that hides fields from (selectable) derive macros in general? `Clone` is the first exception, which we cannot hide from.

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [July 27, 2022, 11:27pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/14 "2022-07-27T23:27:16Z")

</div>

Given that derives get the raw syntax, I'm not sure how that would even work. Userland proc macros get a `TokenStream`, while the built-in macros get the AST. Either way, hiding something with a mechanism would have quite a bit of overhead (duplicating the entire `TokenStream`/AST) and too magical for my taste.

---

<div class="post-metadata">

**Author:** ![synek317](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/synek317/32/3371_2.png) [@synek317](https://internals.rust-lang.org/u/synek317)\
**Post date:** [August 1, 2022, 8:20pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/15 "2022-08-01T20:20:51Z")

</div>

> [@Jules-Bertholet](#):
>
> Rust currently deals with this by not allowing types with custom `Eq` impls to do structural match at all.

@Jules-Bertholet could you elaborate on this?

I did a quick test and this code prints "equal: true, doesn't match"

```rust

struct Thingy(i32, i32);

impl std::cmp::PartialEq for Thingy {
    fn eq(&self, other: &Self) -> bool {
        self.1 == other.1
    }
}

impl std::cmp::Eq for Thingy {}

fn main() {
    let thingy = Thingy(1, 2);
    
    print!("equal: {}, ", thingy == Thingy(99999999, 2));
    
    match thingy {
        // Should the following match succeed?
        Thingy(99999999, 2) => println!("matches!"),
        _ => println!("doesn't match"),
    }
}

```

> **[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5cfae71208b91778444af48015c0a42e)**
>
> A browser interface to the Rust compiler to experiment with the language

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [August 1, 2022, 8:37pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/16 "2022-08-01T20:37:44Z")

</div>

That is a tuple-struct-pattern, not a structural match. Check this:

> **[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8f60f1f2963773957df08117ee5937f0)**
>
> A browser interface to the Rust compiler to experiment with the language

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [August 1, 2022, 8:47pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/17 "2022-08-01T20:47:02Z")

</div>

That’s… actually really confusing given how often `const X = Y` is explained as basically doing a substitution of `X` with `Y` everywhere. I guess patterns are special given their looks-like-expression-but-actually-dual-of-expression nature, but still.

---

<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:** [August 1, 2022, 9:19pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/18 "2022-08-01T21:19:38Z")

</div>

`const` is a hygienic substitution of the computed _value_, not of the expression. Also, consider `const X = some().complex().expression()` instead of `Thingy(99999999, 2)`; you clearly can't just inline an arbitrary expression (as a pattern).

The `StructuralEq` bound is required specifically such that pattern matching a `const` is guaranteed structural and not just `it if it == CONST`.

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [August 1, 2022, 9:31pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/19 "2022-08-01T21:31:29Z")

</div>

> [@CAD97](#):
>
> Also, consider `const X = some().complex().expression()` instead of `Thingy(99999999, 2)`; you clearly can't just inline an arbitrary expression.

(Well, as long as constant expressions can't have side effects, referential transparency says it shouldn't actually matter whether you copypaste the expression or its value, but I digress…)

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [August 2, 2022, 3:11pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/20 "2022-08-02T15:11:33Z")

</div>

I was wrong, as @Nemo157 correctly pointed out.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [October 31, 2022, 3:12pm UTC](https://internals.rust-lang.org/t/cmp-ignore-attribute-for-deriving-eq-ord-hash/17087/21 "2022-10-31T15:12:12Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
