# Pre-RFC: Add \`Forget\` auto trait (again)

**URL:** https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807
**Category:** language design
**Created:** [December 17, 2021, 3:57am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807 "2021-12-17T03:57:53Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 17, 2021, 3:57am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/1 "2021-12-17T03:57:54Z")

</div>

Hi dear Rustaceans, I'm new to this forum and this is the first time I participate in a discussion about language desin, so please forgive me if I made obvious mistakes.

# Background

The `Forget` trait idea has been proposed by several people independently, including [Fixing the `Drop` trait bound](https://internals.rust-lang.org/t/fixing-the-drop-trait-bound/9458), [Pre-Pre-RFC: Forget trait](https://internals.rust-lang.org/t/pre-pre-rfc-forget-trait/5606), in [a reddit thread](https://www.reddit.com/r/rust/comments/4l4wjl/a_report_on_regions_and_linear_types/d3lygjn/), in [a review comment](https://github.com/rust-lang/rfcs/pull/2534#discussion_r244580008).

It was part of a bigger idea in most cases, and when it was independently proposed in [Pre-Pre-RFC: Forget trait](https://internals.rust-lang.org/t/pre-pre-rfc-forget-trait/5606), comments seem to imply lacking motivation and the discusstion drifted to linear types which faded like other threads.

I recently hit a use case where `Forget` is valuable and I'd like to share my case with you.

# Design

`Forget` would be an unsafe auto trait:

```rust
pub unsafe auto trait Forget { }

```

`T` is `Forget` when `std::mem::forget` is a no-op.

This means:

- Primitive types (i32, fn, pointer, shared reference, unit...) are `Forget`.
- A type is `Forget` if all of its components are `Forget` and it is not `Drop`.

It must not be implemented manually (not sure about this) and is a super trait of `Copy`.

`Copy` is modified to:

```rust
pub trait Copy: Clone + Forget { }

```

## Is it just `Copy`?

No. Copy is opt-in. Users can choose to not implement `Copy` when a type is actually `Forget`.

Without the `Forget` trait, we can't tell the difference between `can't implement Copy` and `choose not to implement Copy`.

## Is it just `!Drop`?

No. `!Drop` is a "super trait" of `Forget`. When a type has drop glue but is not `Drop`, it's not `Forget`.

## Is it backwards compatible?

Looks like so to me. `Copy` can't be implemented on non-`Forget` types now.

# Motivation

I was writing a 3D renderer based on [wgpu](https://github.com/gfx-rs/wgpu). `wgpu`, like any other graphics libraries, exposes interfaces accepting raw `&[u8]` buffers and a type descriptor (for example [IndexFormat](https://docs.rs/wgpu/0.11.1/wgpu/enum.IndexFormat.html)). My abstraction for this is [type\_erased\_vec - Rust](https://docs.rs/type_erased_vec/latest/type_erased_vec/).

A type `T` can be put into [TypeErasedVec](https://docs.rs/type_erased_vec/latest/type_erased_vec/struct.TypeErasedVec.html) when it's `Forget`, because the `Drop` implementation of `TypeErasedVec` lacks type information and doesn't run `T`'s destructor.

Now I used the bound `T: Copy`, which is overly restrictive as expalined before. I can't see a workaround without `Forget`.

I expect this situation happening often when people manage memory manually and need to know if some memory can be simply deallocated without running user code.

That's it! Any feedback will be appreciated!

---

<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: [December 17, 2021, 5:55am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/2 "2021-12-17T05:55:28Z")

</div>

> Is it just `!Drop`?  
> No. `!Drop` is a "super trait" of `Forget`. When a type has drop glue but is not `Drop`, it's not `Forget`.

If we "fix" `T: Drop` bounds to mean "has drop glue," add `!Trait` bounds for "explicitly promises never to impl `Trait`, and make `Copy: !Drop` in the type system (all plausibly discussed previously), how does `Forget` differ from `!Drop`?

I think just that `Forget` is an auto-trait. I don't know if jt being an auto-trait is desirable; adding a `Drop` impl can already be breaking (can change when borrows end, interactions with the borrowck eye patch (`#[may_dangle]`)), and `Forget` would turn it into a much more direct breakage.

> [@chubei](#):
>
> TypeErasedVec

I just glanced at it, but providing `&(ptr, len, cap) as &Vec` is (library) UB, and always will be. Additionally, providing `&Vec<T, A> as &Vec<T, Global>` is also (library) UB, and always will be. `#[repr(Rust)]` layout is not defined, and you _must not_ assume any details about how such types are laid out.

Also, if your types have padding in them, `&[T] as &[u8]` is _also_ UB, because padding bytes are uninitialized.

> [@chubei](#):
>
> Motivation  
> ... wgpu ... the bound `T: Copy` , which is overly restrictive as expalined before. I can't see a workaround without `Forget` .

You probably want [`bytemuck::Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html).

It's always _safe_ to `mem::forget` something, so it's never unsound to transmute a `Pod` type into `[u8; size_of::<T>()]`. It _could_ potentially skip a destructor (`Pod` does not forbid drop glue), but it'd be a very surprising implementation of `Pod` (alongside other misimplementation of safe traits: unintended behavior, but not unsound behavior).

Along those same lines, `Forget` should be a safe trait, as implementing it will never lead to unsound behavior, just skipping drop glue, which is never unsound behavior.

> [@chubei](#):
>
> know if some memory can be simply deallocated without running user code

At runtime (or `const` time!), [`mem::needs_drop`](https://doc.rust-lang.org/stable/std/mem/fn.needs_drop.html) (though tbf it's only a hint and is allowed to spuriously say `true`).

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 17, 2021, 6:51am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/3 "2021-12-17T06:51:02Z")

</div>

> [@CAD97](#):
>
> If ... how does `Forget` differ from `!Drop` ?

No difference at all. `Has no drop and has no drop glue` is the whole purpose of `Forget`. But changing the meaning of `Drop` would be a breaking change? So `Forget` is my last resort.

> [@CAD97](#):
>
> providing `&(ptr, len, cap) as &Vec` is (library) UB

Thanks! I was not aware of this. Is it UB even if (ptr, len, cap) was returned from [Vec::into\_raw\_parts](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_raw_parts)? This claim seems to beat the purpose of [Vec::from\_raw\_parts](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts)?

> [@CAD97](#):
>
> providing `&Vec<T, A> as &Vec<T, Global>` is also (library) UB

Is it so when I can't deallocate/reallocate the memory? I mean, Given a `&Vec<T, Global>`, all I can do is to get its len/cap or clone it.

EDIT: I realized that this breaks the invariant that `ptr` is allocated with `A`. I should probably remove this interface.

> [@CAD97](#):
>
> You probably want [`bytemuck::Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html)

Yes, in the 3D renderer I use `Pod`. But in `TypeErasedVec`, `Pod` is even more restrictive than `Copy`.

> [@CAD97](#):
>
> `Forget` should be a safe trait

Good point! Agreed!

---

<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: [December 17, 2021, 9:12am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/4 "2021-12-17T09:12:00Z")

</div>

> [@chubei](#):
>
> Without the `Forget` trait, we can't tell the difference between `can't implement Copy` and `choose not to implement Copy` .

> [@CAD97](#):
>
> add `!Trait` bounds for "explicitly promises never to impl `Trait`

Note that this already exists in nightly, and is being expanded with [negative impls integrated into coherence · Issue #96 · rust-lang/lang-team · GitHub](https://github.com/rust-lang/lang-team/issues/96)

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 17, 2021, 12:13pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/5 "2021-12-17T12:13:04Z")

</div>

We can do `impl !Trait` on nightly but can't do `where T: !Trait`. And negative bound can't help tell the difference unless meaning of `Drop` is modified, right?

---

<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: [December 17, 2021, 12:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/6 "2021-12-17T12:14:02Z")

</div>

> [@chubei](#):
>
> Is it UB even if (ptr, len, cap) was returned from [Vec::into\_raw\_parts](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_raw_parts)? This claim seems to beat the purpose of [Vec::from\_raw\_parts](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts)?

The purpose of `into_raw_parts` is that you can use the raw parts individually, and perhaps later give them to `Box::from_raw` (as a slice of the full capacity) or `Vec::from_raw_parts`.

You _must not ever_ transmute/cast from `&T` to `&U` when either type is `#[repr(Rust)]` (with _very_ specialized exceptions[1]), because `#[repr(Rust)]` is _unspecified_. This means you do not know the field order, and it could change for any reason (there's even a flag to randomize field order). This even applies to e.g. `Box<T, A>` and `Box<U, A>`! It is never valid to treat the bytes of one `#[repr(Rust)]` type as valid for another type (except for the aforeündermentioned exceptions) because of this.

[My own erased thin pointer abstraction](https://docs.rs/erasable/latest/erasable/struct.Thin.html#method.with) provided a closure callback based API for this reason. It's not the most ergonomic, but it is sound.

> [@chubei](#):
>
> But changing the meaning of `Drop` would be a breaking change?

Given that a `T: Drop` bound warns, has warned for a long time, and is functionality useless, my understanding was that last time it was discussed, it was considered fine to expand the set of types which fulfill that bound to be more correct. All types fulfilling the bound would be _correct_ (as all types can be dropped), but I do think types with drop glue is a more actually useful meaning.

Either way, what would _actually_ be useful would be `!Drop` anyway, which would cover `Copy` types and any other type which had explicitly `impl !Drop for T` to promise never to have drop glue. (Which also makes adding drop glue more immediately breaking, I suppose. I do think it's already effectively breaking, iirc, just less obviously so.)

* * *

~~If you want a better "doesn't have drop glue," though, you can cobble it together fairly easily now, even with min const generics, before boolean logic is more tightly integrated into `where` clauses:~~

~~

```rust
// roughly
trait True {}
trait False {}
struct Bool<const B: bool>;
impl True for Bool<true> {}
impl False for Bool<false> {}

trait Forget {}
impl<T> Forget for T
where Bool<{ mem::needs_drop::<T>() }>: False
{}

```

~~

~~..... this means `needs_drop` isn't just a hint at `const` time and needs to be implemented properly to detect the presence of drop glue. I don't know if this was discussed when it was made stably `const`; either way, the docs probably should be updated to reflect this.~~

Scratch that bit, type parameters can't be used in const parameters yet. (The fact that a `const fn needs_drop` needs to be accurate stands, though; you can have it in the type system for concrete `T`.)

* * *

[1] the exceptions are built-in types, which still technically are `#[repr(Rust)]` but have a defined layout — `iNN`, `uNN`, `bool`, `[T; N]`, `[T]`, `*const T`, `*mut T`, `&T`, and `&mut T` — library types with a guaranteed layout — `ptr::NonNull<_>` and `Box<_, Global>` — and "`Option`-like enums" (ones with one data variant and one unit variant), which are guaranteed to use the null value for the unit variant if (and only guaranteed if) the data variant is a non null pointer type.

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 17, 2021, 12:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/7 "2021-12-17T12:41:11Z")

</div>

Thanks for the detailed explanation!

I've modified `TypeErasedVec` to use only `Vec::from_raw_parts_in` to produce a `Vec<T, A>`. Hope it's sound after all.

If people tend to go with modifying the meaning of `Drop`, I guess I'll live with `Copy` now and wait for a new RFC once people agree on how negative trait bound should work.

---

<div class="post-metadata">

### Author: ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)
#### Post date: [December 17, 2021, 12:46pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/8 "2021-12-17T12:46:36Z")

</div>

> [@CAD97](#):
>
> It _could_ potentially skip a destructor ( `Pod` does not forbid drop glue), but it'd be a very surprising implementation of `Pod` (alongside other misimplementation of safe traits: unintended behavior, but not unsound behavior).

If you're referring to `Pod` from bytemuck, it does. `Pod: Copy + 'static`

---

<div class="post-metadata">

### Author: ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)
#### Post date: [December 17, 2021, 2:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/9 "2021-12-17T14:51:21Z")

</div>

`Forget` seems like `NoDropGlue`, so something along the lines of:

```rust
unsafe auto trait NoDropGlue {}
impl<T : Drop> !NoDropGlue for T {}

```

, assuming the case of "neither `T : Trait` nor `T : !Trait` hold" works correctly: "given `T : ?Drop`, we should have `T : ?NoDropGlue`" _etc._

In that case, indeed, we could add `NoDropGlue` as a super-trait of `Copy`, since the compiler already enforces this.

* * *

@chubei would such an auto-trait definition suit your use case? Also, FWIW, you could take the approach of `::uninit`, and offer a "potentially leaking" API for non-`Copy` types ([an example](https://docs.rs/uninit/latest/uninit/extension_traits/trait.VecCapacity.html#method.get_backing_buffer_with_leaking_writes)):

- Another example: [uninit::extension\_traits::ManuallyDropMut - Rust](https://docs.rs/uninit/latest/uninit/extension_traits/trait.ManuallyDropMut.html#example)

---

<div class="post-metadata">

### Author: ![notriddle](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/notriddle/32/14082_2.png) [@notriddle](https://internals.rust-lang.org/u/notriddle)
#### Post date: [December 17, 2021, 8:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/10 "2021-12-17T20:33:32Z")

</div>

> [@CAD97](#):
>
> Given that a `T: Drop` bound warns, has warned for a long time, and is functionality useless, my understanding was that last time it was discussed, it was considered fine to expand the set of types which fulfill that bound to be more correct.

Wouldn't that break [pin-project](https://github.com/taiki-e/pin-project/blob/262b84b20e9406d882dc813063345b5150251e1c/pin-project-internal/src/pin_project/derive.rs#L862-L875)?

---

<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: [December 17, 2021, 10:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/11 "2021-12-17T22:21:54Z")

</div>

> [@CAD97](#):
>
> I do think it's already effectively breaking, iirc, just less obviously so.

If it has public fields it's very breaking, as adding `Drop` prevents moving out fields, even with ownership: [https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4b39a12043150726ed51877dd0487fbe](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4b39a12043150726ed51877dd0487fbe)

---

<div class="post-metadata">

### Author: ![felix.s](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/felix.s/32/8073_2.png) [@felix.s](https://internals.rust-lang.org/u/felix.s)
#### Post date: [December 18, 2021, 12:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/12 "2021-12-18T12:34:33Z")

</div>

> [@CAD97](#):
>
> If we "fix" `T: Drop` bounds to mean "has drop glue," add `!Trait` bounds for "explicitly promises never to impl `Trait` , and make `Copy: !Drop` in the type system (all plausibly discussed previously), how does `Forget` differ from `!Drop` ?

It avoids the law of excluded middle, and brings us closer to the world in which trait bounds are always positive assumptions or capabilities: a trait bound not being met means merely means you cannot _assume_ certain properties or _access_ certain operations, even if they may be available to someone else, or in the future. This simplifies reasoning about code and makes adding a trait implementation always a backwards-compatible change.

Plus, defining `T: Drop` to mean ‘automatic disposal is _possible_’ instead of ‘automatic disposal is _non-trivial_’ opens the door to adding true linear types, if we ever decide to do so.

---

<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: [December 18, 2021, 3:13pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/13 "2021-12-18T15:13:27Z")

</div>

> [@felix.s](#):
>
> makes adding a trait implementation always a backwards-compatible change

To be clear: adding any drop glue is already a breaking change. (I've now been convinced this is always true.) Also, `T: !Trait` is a) planned, at least for coherence purposes, even if not directly in bounds; and b) only true if the trait is _explicitly_ promised to not be implemented, not just that it happens to not be implemented. (And I believe the expectation will be to only impl the negative trait when it would be _wrong_ to implement the trait. The _big_ one that currently exists is `!DerefMut for &T`.)

This means that the middle isn't excluded; it's a deliberately considered design goal that the default position is safe to evolve and implement more traits.

* * *

Back on the OP though... the `Forget` trait doesn't add any new functionality. You can still `mem::forget` any type; `Forget` is just a marker trait that forgetting the type is "non problematic."

I think that because of this it doesn't really hold enough value to merit being in the standard library. Your type tag can either hold a function pointer to `drop_in_place::<T>` to implement dropping, or if it's going to be `ManualDrop`py, you can make an easy constructor for types known to have no drop glue (`Copy`) and an annoying one for the rest that require wrapping in `ManualDrop` to make the drop suppression clear (or just make it in the name of the constructor).

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 20, 2021, 2:39am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/14 "2021-12-20T02:39:36Z")

</div>

> [@dhm](#):
>
> would such an auto-trait definition suit your use case

Yes! Exactly what I need.

> [@dhm](#):
>
> offer a "potentially leaking" API for non- `Copy` types

Great idea! I'll think about what a "leaking API" looks like.

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 20, 2021, 2:56am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/15 "2021-12-20T02:56:25Z")

</div>

> [@CAD97](#):
>
> hold a function pointer to `drop_in_place::<T>` to implement dropping

This is off-topic but interesting... I don't think this is possible. Type of `drop_in_place::<T>` is `unsafe fn(*mut T)`, which is not type-erased and can not be held in `TypeErasedVec`.

---

<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: [December 20, 2021, 12:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/16 "2021-12-20T12:51:15Z")

</div>

> [@chubei](#):
>
> Type of `drop_in_place::<T>` is `unsafe fn(*mut T)` , which is not type-erased and can not be held in `TypeErasedVec` .

Can't you wrap it? Something like this:

```rust
struct Erased; // XXX: Can this be a ZST?
let drop_erased = |ptr: *mut Erased| {
    // SAFETY: Will only ever pass in `self.erased.as_ptr()`
    drop_in_place::<T>(unsafe { ptr as *mut T })
};
// Put `drop_erased` into the vec

```

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 20, 2021, 12:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/17 "2021-12-20T12:57:08Z")

</div>

Can't put `drop_erased` into the Vec because it's a closure and can't have its type named.

---

<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: [December 20, 2021, 1:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/18 "2021-12-20T13:00:15Z")

</div>

You can coerce that closure into a function pointer `unsafe fn(*mut Erased)` since it's stateless (or just define it as a `fn` in the first place).

---

<div class="post-metadata">

### Author: ![chubei](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chubei/32/8712_2.png) [@chubei](https://internals.rust-lang.org/u/chubei)
#### Post date: [December 20, 2021, 1:19pm UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/19 "2021-12-20T13:19:13Z")

</div>

Yes! Brilliant solution. I'll try it!

---

<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: [January 4, 2022, 2:42am UTC](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807/20 "2022-01-04T02:42:54Z")

</div>

> [@CAD97](#):
>
> If we "fix" `T: Drop` bounds to mean "has drop glue," add `!Trait` bounds for "explicitly promises never to impl `Trait` , and make `Copy: !Drop` in the type system (all plausibly discussed previously), how does `Forget` differ from `!Drop` ?

In general, a type that implements a trait is strictly more useful than a type that doesn't implement that trait. `Drop` is the ugly exception to this rule. The proposal to "fix" `!Drop` would make it a double-negative (a type is `!Drop` if it's not _not_ able to be used in situations where only drop-glue free types can be used), which is arguably confusing.

What if we instead used `Forget` for this purpose, and replaced `Drop` with `!Forget`? `!Forget` would become a "special" negative impl that has a method (though user code can't call that method directly):

```rust
// In `core`

#[lang = ...]
pub auto trait Forget {}

// `Forget` is special so it can do this
pub trait !Forget {
    /// User code can't call this directly.
    /// Note the empty default implementation:
    /// Types which are `!Forget` only because they contain a `!Forget` type
    /// use this empty impl
    fn drop(&mut self) {}
}

pub type Drop = !Forget; // For backward compatibility

```

```rust
// User code

pub struct Foo {}

impl !Forget for Foo {
    fn drop(&mut self) {
        // Drop glue
    }
}

```

This alternative syntax has the advantage of ensuring that "implementing a trait makes your type strictly more useful" always holds, avoiding the `!Drop` "double-negative".

* * *

Note: currently `!Trait` syntax implies a semver commitment to never implement a trait for a type, so under this syntax there is technically no way to express "this type currently has drop glue, but I might get rid of it later". This isn't a huge issue though given that current Rust can't express this either, and in any case removing drop glue isn't actually breaking in practice (if it was, the motivation for this new syntax would be invalid).

However, if a no-semver-commitment negative impl syntax is desired, maybe `impl ?Forget` or `!impl Forget` would work? This would be useful for other auto-traits as well.

[Next page](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807.md?page=2)
