# (Pre-)RFC for ExplicitDrop

**URL:** <https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370>\
**Category:** language design\
**Created:** [May 18, 2020, 7:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370 "2020-05-18T19:26:59Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jasper-Bekkers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jasper-bekkers/32/6835_2.png) [@Jasper-Bekkers](https://internals.rust-lang.org/u/Jasper-Bekkers)\
**Post date:** [May 18, 2020, 7:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/1 "2020-05-18T19:26:59Z")

</div>

I have a language features / stdlib thing that I'm thinking of proposing an RFC for, but would like to get some feedback on.

The problem is; I have some resource that don't live on the CPU timeline (they live on a GPU timeline); so using RAII or rust lifetime tracking in general makes relatively little sense for them. The concept of a "scope" in rust doesn't apply to them.

Right now these resources are explicitly free'd through some mechanism; however, they can't implement Drop properly (because scope doesn't apply & deleting the resource in Drop would be a race condition with the GPU).

The proposal is relatively straight forward; have a trait like `ManuallyDrop` , called `ExplicitDrop` which would invoke a compile error whenever the compiler would've otherwise dropped the object (e.g. I can only move it around, and take borrows of it). To get rid of the object and to clean it up, an explicit call to `drop` would be needed.

---

<div class="post-metadata">

**Author:** ![jschievink](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jschievink/32/3063_2.png) [@jschievink](https://internals.rust-lang.org/u/jschievink)\
**Post date:** [May 18, 2020, 7:45pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/2 "2020-05-18T19:45:17Z")

</div>

Sounds like linear types. I suggest reviewing the previous work on that.

(for example, [https://gankra.github.io/blah/linear-rust/](https://gankra.github.io/blah/linear-rust/))

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [May 18, 2020, 7:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/3 "2020-05-18T19:58:35Z")

</div>

I wonder if the link failure trick that [https://docs.rs/no-panic/0.1.13/no\_panic/](https://docs.rs/no-panic/0.1.13/no_panic/) uses could also be applied to destructors while still permitting some kind of explicit drop. Has anyone ever messed with that?

(regarding "deep" or "first-class" support for must-use-once/linear types, I still basically agree with that classic Gankra post that it's more trouble than it's worth, but "shallow" options that are just a notch up from `ManuallyDrop` may be worth considering)

---

<div class="post-metadata">

**Author:** ![Jasper-Bekkers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jasper-bekkers/32/6835_2.png) [@Jasper-Bekkers](https://internals.rust-lang.org/u/Jasper-Bekkers)\
**Post date:** [May 18, 2020, 8:04pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/4 "2020-05-18T20:04:14Z")

</div>

That post highlights the problem quite nicely, and references the solution I'm currently thinking of implementing (assert / panic in Drop) which is a bit less then ideal.

---

<div class="post-metadata">

**Author:** ![jschievink](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jschievink/32/3063_2.png) [@jschievink](https://internals.rust-lang.org/u/jschievink)\
**Post date:** [May 18, 2020, 8:35pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/5 "2020-05-18T20:35:13Z")

</div>

> [@Ixrec](#):
>
> I wonder if the link failure trick that [https://docs.rs/no-panic/0.1.13/no\_panic/](https://docs.rs/no-panic/0.1.13/no_panic/) uses could also be applied to destructors while still permitting some kind of explicit drop. Has anyone ever messed with that?

Yup, [here](https://github.com/jamesmunns/undroppable/blob/683045baed7906b504da9ce6039752fe94d19eab/src/lib.rs).

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [May 18, 2020, 11:22pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/6 "2020-05-18T23:22:17Z")

</div>

There’s a micro crate with cool readme for that: [https://github.com/matklad/drop\_bomb](https://github.com/matklad/drop_bomb)

Though, most of the time it makes sense to just write the thing yourself.

---

<div class="post-metadata">

**Author:** ![Jasper-Bekkers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jasper-bekkers/32/6835_2.png) [@Jasper-Bekkers](https://internals.rust-lang.org/u/Jasper-Bekkers)\
**Post date:** [May 19, 2020, 12:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/7 "2020-05-19T12:30:09Z")

</div>

So it looks like there's a need for this, both from this thread, talking to a few other developers and the fact that some crates already exist to address this need. For example: I found the `drop_bomb` during already during research for this, as well as [https://crates.io/crates/humpty\_dumpty](https://crates.io/crates/humpty_dumpty) which tries to do a similar thing as a linting extension.

It looks like the community already has put some thought behind this, are there any existing RFC's that I should be aware of for similar things?

---

<div class="post-metadata">

**Author:** ![ApoorvaJ](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/apoorvaj/32/1677_2.png) [@ApoorvaJ](https://internals.rust-lang.org/u/ApoorvaJ)\
**Post date:** [May 19, 2020, 12:45pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/8 "2020-05-19T12:45:03Z")

</div>

Like Jasper, I've also hit this problem, while working with the Vulkan GPU API.

I implement drop traits everywhere I can. But some things can only have one valid instance (for instance, the swapchain). Here, it is impossible to use drop traits, because you would need to create a new instance before the older one can be dropped.

The alternative, of course, is to wrap the swapchain in an Option, and then set it to None, forcing a drop. This feels feels too icky, because IMO it diverges from the semantic meaning of an Option, and because you have to unwrap it everywhere.

I just end up defining a `destroy()` function, and having to remember to manually call it. It would be useful to get a compiler error if I forget to destroy these resources.

To that end, Jasper's proposal sounds interesting. I'm looking forward to seeing where it goes.

---

<div class="post-metadata">

**Author:** ![idanarye](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/idanarye/32/3346_2.png) [@idanarye](https://internals.rust-lang.org/u/idanarye)\
**Post date:** [May 20, 2020, 1:09am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/9 "2020-05-20T01:09:19Z")

</div>

This is going to cause problems with error handling:

```rust
fn foo() -> Result<(), QuxError> {
    let bar = SomeExplicitDropType::new();
    bar.baz(qux()?);
    bar.explicit_drop();
    Ok(())
}

```

If `qux()` returns an error, `bar` will not be explicitly dropped - so the compiler will not allow it. Any usage of `?` in the presence of `ExplicitDrop` types will fail to compile.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 20, 2020, 1:43am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/10 "2020-05-20T01:43:53Z")

</div>

I think this is fine, (these are the exact cases we want to fail to compile). Rewritting these portions shouldn't be that much of a burden, esp if it's only a small portion of your codebase.

How will this interact with putting these types in other types? i.e.

```rust
struct Foo;
struct Bar(Foo);

struct ExplicitDrop for Foo {
    fn explicit_drop(self) {}
}

fn bar(b: Bar) {
    // what happens here?
}

```

How about generic functions?

```rust
fn generic<T>(t: T) {}

fn foo() {
    generic(Foo);
}

fn bar() {
    generic(Bar(Foo));
}

```

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 20, 2020, 6:26am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/11 "2020-05-20T06:26:50Z")

</div>

I suppose what is needed for proper generics while keeping backwards compatibility is that actually “implicit drop” capability becomes a trait (`ImplicitDrop`, say -- the [blog post on linear types](https://gankra.github.io/blah/linear-rust/) calls it `Leave`), which is however automatically put into generic bounds, much like `Sized` is. This would still require any generic function that wants to support the new types without implicit drop capabilities to update its type parameters to `T: ?ImplicitDrop`; that’s a backwards-compatible change, too.

Furthermore, this trait would probably best be an `auto trait` so that structs containing any `!ImplicitDrop` fields are themselves `!ImplicitDrop`.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 20, 2020, 6:46am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/12 "2020-05-20T06:46:05Z")

</div>

A point not mentioned here yet is: How is this supposed to interoperate with panics? Usually during stack unwinding, everything gets dropped. I can thing of several approaches:

- It is okay for an “explicit drop”-value to be dropped in a panic, since panics are special
- It is only okay to `abort`, since `panic`s could be caught. Enforcing this might be best done with some sort of static analysis on whether panics might be possible.
- An “explicit drop”-value on the stack in a function makes it implicitly convert all panics going through it into aborts. (Much like if the `drop` implementation panics.)

I guess the last option might be the best one, since it fits into the picture of what currently happens when a `Drop` impl panics.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 20, 2020, 9:53am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/13 "2020-05-20T09:53:49Z")

</div>

> [@steffahn](#):
>
> A point not mentioned here yet is: How is this supposed to interoperate with panics?

Yes, the last option seems best.

---

<div class="post-metadata">

**Author:** ![Jasper-Bekkers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jasper-bekkers/32/6835_2.png) [@Jasper-Bekkers](https://internals.rust-lang.org/u/Jasper-Bekkers)\
**Post date:** [May 20, 2020, 11:19am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/14 "2020-05-20T11:19:34Z")

</div>

> [@steffahn](#):
>
> Furthermore, this trait would probably best be an `auto trait` so that structs containing any `!ImplicitDrop` fields are themselves `!ImplicitDrop` .

Doing this as an `auto trait` would make a lot of sense; as does flipping it to `ImplicitDrop`.

> [@RustyYato](#):
>
> How will this interact with putting these types in other types? i.e.
> 
> ```rust
> struct Foo;
> struct Bar(Foo);
> 
> struct ExplicitDrop for Foo {
> fn explicit_drop(self) {}
> }
> 
> fn bar(b: Bar) {
> // what happens here?
> }
> 
> ```

In this case `bar` would need to drop the `Foo` in `Bar` explicitly.

> [@steffahn](#):
>
> A point not mentioned here yet is: How is this supposed to interoperate with panics? Usually during stack unwinding, everything gets dropped. I can thing of several approaches:

I'm not sure about the semantic differences between `panic` and `abort, but I think your last option might be the right one - IMHO it's fine to rely on OS cleanup for these things but I don't know the Rust policy on this.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 20, 2020, 11:54am UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/15 "2020-05-20T11:54:37Z")

</div>

I would like to throw in the question whether an even better approach would be not to require calls to `drop` to be explicit but instead disallow calling `drop` (implicitly or explicitly) entirely. This would mean that the only way to get rid of a value is destructuring. Additionally, explicit `drop` could be allowed in any place where destructuring is _possible_ (due to all the fields being visible). Going this route, even implicit drops may be allowed when all the fields are visible (which is usually only possible internally in the implementation of the type). In the last case, we should disallow (or warn about) types being `!ImplicitDrop` even though all their fields are (globally) public and themselves `ImplicitDrop`, since in this case an implicit (or explicit) drop would actually still be possible. [With an `auto trait ImplicitDrop` this means that the negative `!ImplicitDrop` impl is explicit; the error (or warning) would point to that impl.]

Note that with the changes in the previous paragraph, the name `ImplicitDrop` wouldn’t make any sense anymore, since the trait would be about whether the type is droppable at all.

Another thing I’ve just noticed: Logically `ImplicitDrop` would have to be a supertrait of `Copy`. I’m not sure about the backwards compatibility issues around actually making it a supertrait.

---

<div class="post-metadata">

**Author:** ![Jasper-Bekkers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jasper-bekkers/32/6835_2.png) [@Jasper-Bekkers](https://internals.rust-lang.org/u/Jasper-Bekkers)\
**Post date:** [May 20, 2020, 12:04pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/16 "2020-05-20T12:04:03Z")

</div>

> [@steffahn](#):
>
> This would mean that the only way to get rid of a value is destructuring

I have a feeling this may be a bit overkill, of have implications that are harder to foresee, do you have any examples of what this would look like? I'm trying to gouge what kind of impact this would have on my particular example.

---

<div class="post-metadata">

**Author:** ![Diggsey](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/diggsey/32/6311_2.png) [@Diggsey](https://internals.rust-lang.org/u/Diggsey)\
**Post date:** [May 20, 2020, 12:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/17 "2020-05-20T12:07:44Z")

</div>

For this use-case you can use `ManuallyDrop`, linear types are not required.

You could even make a safe wrapper for this pattern using procedural macros. (Something similar to how `PinnedDrop` works from the `pin_project` crate)

---

<div class="post-metadata">

**Author:** ![idanarye](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/idanarye/32/3346_2.png) [@idanarye](https://internals.rust-lang.org/u/idanarye)\
**Post date:** [May 20, 2020, 12:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/19 "2020-05-20T12:14:03Z")

</div>

> [@steffahn](#):
>
> Additionally, explicit `drop` could be allowed in any place where destructuring is _possible_ (due to all the fields being visible).

But destructuring is also possible with private fields with "`..`".

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [May 20, 2020, 12:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/20 "2020-05-20T12:32:19Z")

</div>

> [@idanarye](#):
>
> But destructuring is also possible with private fields with " `..` ".

Good point. At least as long as they don’t implement `Drop`.

I think what we need in this discussion is some concrete examples to find out which approach is best.

> [@Jasper-Bekkers](#):
>
> I'm trying to gouge what kind of impact this would have on my particular example.

May you be able to make your example more concrete? I’m actually not quite sure how exactly you envisioned your `ExplicitDrop` to be used in the first place. In particular I don’t know if such a type explicitly implements `Drop` or not and if yes, how, and what an explicit call to `drop` would do, etc..

---

<div class="post-metadata">

**Author:** ![Jasper-Bekkers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jasper-bekkers/32/6835_2.png) [@Jasper-Bekkers](https://internals.rust-lang.org/u/Jasper-Bekkers)\
**Post date:** [May 20, 2020, 2:18pm UTC](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370/21 "2020-05-20T14:18:08Z")

</div>

> [@steffahn](#):
>
> May you be able to make your example more concrete? I’m actually not quite sure how exactly you envisioned your `ExplicitDrop` to be used in the first place. In particular I don’t know if such a type explicitly implements `Drop` or not and if yes, how, and what an explicit call to `drop` would do, etc..

I've created a playground for it (that obviously doesn't run) [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a20b087f8ab289a3ecfc00609cf38c5d) in this particular case, the expectation would be that `MyObject` derives `ExplicitDrop`.

[Next page](https://internals.rust-lang.org/t/pre-rfc-for-explicitdrop/12370.md?page=2)
