# Barriers for \`derive\`

**URL:** <https://internals.rust-lang.org/t/barriers-for-derive/7137>\
**Category:** Uncategorized\
**Created:** [March 25, 2018, 4:52pm UTC](https://internals.rust-lang.org/t/barriers-for-derive/7137 "2018-03-25T16:52:50Z")\
**Posts on this page:** 4\
**Page:** 1

<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:** [March 25, 2018, 4:52pm UTC](https://internals.rust-lang.org/t/barriers-for-derive/7137/1 "2018-03-25T16:52:50Z")

</div>

Sometimes I want a type `T` to implement some trait (e.g. `PartialEq`) but prevent other types containing `T` from deriving that trait.  
This post is a question about how to achieve this better.

As a concrete examples, I’ll look at `Span` and `Ident` in the compiler, because I’ve recently noticed that careless deriving of `PartialEq` for structures containing spans and identifiers created a mine field of bugs in macro expansion. Constructions that are commonly used by people are now bug-free, but [step to the left or step to the right](https://github.com/rust-lang/rust/pull/49326) and things stop working.

Spans can be reasonably compared themselves, but _usually_ if they are used in larger structures they serve informational purpose, e.g. one token tree should be equal to another identical token tree regardless of where it’s located in the source file.  
Identifiers are a bit different - they can be reasonably compared hygienically, but before the comparison you may want to tweak some contexts or you may want to compare unhygienically in some cases. Larger structures need to decide how exactly they want to compare identifiers.

So I want a way to create a barrier for `derive(PartialEq)` on structures containing `Span` or `Ident`.  
If someone tries to derive, they should see a message **“STOP! THINK!”** and write implementation of `PartialEq` manually, or not write it at all and write something more flexible instead.

* * *

One possible solution is to capitulate and not to implement `PartialEq` and add a separate comparison function instead.  
Then you can use something like `Ident::equal(i1, i2)` for comparisons and something like `ComparableIdent` wrapper for maps/sets (`HashMap<ComparableIdent, Value>`).  
I tried this approach, it’s workable but not convenient and involves some amount of suffering.

Any better solution?  
(Possibly including enhancements to `derive.`)

---

<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:** [March 25, 2018, 5:09pm UTC](https://internals.rust-lang.org/t/barriers-for-derive/7137/2 "2018-03-25T17:09:59Z")

</div>

The flip side to your solution is to implement `PartialEq` on the base type, and then use a non-`PartialEq` wrapper in contexts where you really don’t want it compared. I guess it depends which should be the default case.

---

<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:** [March 25, 2018, 6:18pm UTC](https://internals.rust-lang.org/t/barriers-for-derive/7137/3 "2018-03-25T18:18:06Z")

</div>

> [@petrochenkov](#):
>
> Any better solution?
> 
> (Possibly including enhancements to derive.)

From a purely technical standpoint (and not whether we should support this), some form of annotation could work:

```rust
#[derive(PartialEq)]
#[derive_final] // Unbounded bikeshed on naming...
struct Foo {
    // Fields...
}

```

or just:

```rust
#[derive_final(PartialEq)]
struct Foo {
    // Fields...
}

```

This has a few problems tho.

1. There is no way for custom derive macros to know whether `#[derive_final]` was done on the type of an field inside the currently-being-derived type.
  - This can be solved by passing such information to the derive macro, but then deriving becomes other than strictly textual (on the text of the type definition), and you will need parts or the whole text of other referenced types in the fields or variants.
  - This solution in turn creates other problems around compiler phases.

2. This only gives a measure of protection for `#[derive(..)]` but no mechanism for protecting bad equivalent `impl`s.

Another way to solve 1. is by adding `eq_final`:

```rust
pub trait PartialEq<Rhs: ?Sized = Self> {
    fn eq(&self, other: &Rhs) -> bool { self.eq_final(other) }
    fn eq_final(&self, other: &Rhs) -> bool;
}

```

And then we `#[derive_final]` with:

```rust
#[derive_final(PartialEq)]
struct Foo(u8);

// Generates:
impl PartialEq for Foo {
    fn eq(&self, other: &Rhs) -> bool {
         self.0.eq_final(&other.0)
    }
    fn eq_final(&self, other: &Rhs) -> bool {
         panic!("PartialEq for Foo is #[derive_final]")
    }
}

```

And when we add a normal derive on top of that, we get:

```rust
#[derive(PartialEq)]
struct Bar(Foo);

// Generates:
impl PartialEq for Foo {
    fn eq_final(&self, other: &Rhs) -> bool { self.0.eq_final(&other.0) }
}

```

Now, when you try to execute `Bar::eq_final` or `Bar::eq`, you will get a `panic!`. However, this mechanism is quite invasive and also uses dynamic correctness checks, which is ungreat.

---

<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:** [March 25, 2019, 8:29am UTC](https://internals.rust-lang.org/t/barriers-for-derive/7137/4 "2019-03-25T08:29:57Z")

</div>

Closed on March 25, 2019, 8:29am UTC

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