# Pre-RFC: allow by-value drop

**URL:** <https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845>\
**Category:** ideas (deprecated)\
**Created:** [April 8, 2015, 4:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845 "2015-04-08T16:10:52Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [April 8, 2015, 4:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/1 "2015-04-08T16:10:52Z")

</div>

# Proposal

Currently, Drop in rust is always by-reference - the object still needs to be valid for drop-glue after the call to `Drop::drop`. An elegant way to fix this is to add a trait (e.g. `Destruct`):

```rust
#[lang="destruct"]
pub trait Destruct {
    fn destroy(self) {
        // This isn't really legal Rust, but the "implicit"
        // impl should be this.
        <Drop as Self>::drop(&mut self);
        let Self { .. } = self;
    }
}

```

The trait should work like `Drop`, except that you can destructure self on objects that have it (of course, to avoid infinite recursion, the implementation of `destroy` has to eventually destructure or leak `self`).

## Privacy Issues

Currently, in Rust, you can destructure a destructor-less object, even if it has private fields:

```
pub mod m { pub struct S(u32); }
mod b { use m::S; pub fn foo(s: S) { let S { .. } = s; } }

```

This is problematic with `Destroy`, because other modules can call this, and lose the structure without calling the destructor. The problem is avoided with `Drop` by preventing all destructuring, which basically breaks `Destroy` (unless you do a manual destructuring by getting a raw pointer to `self`, `ptr::read`-ing all fields, and then forgetting `self`, but this _is_ quite ugly).

To allow for sane usage of `Destroy`, we can either force destructuring of a type with an explicit `Destroy` impl to mention all fields, or just forbid destructuring of types with an explicit `Destroy` impl and inaccessible (because of privacy) fields.

## Misc. Details

The same destructor-lifetime rules that apply to impls of `Drop` should also apply to impls of `Destroy`. A single type implementing both `Drop` and `Destroy` shall cause a compile-time error, as if there was an `impl<T:⁠ Drop> Destroy for T`.

Currently, the trait `Destroy` isn’t object-safe, as it has a by-value `self`. However, vtables (for `Box<Trait>`) need to have a way to call it. Because of ABI issues, this could require a shim. We already have a drop-glue shim, through, so we can just adapt it.

# Issues

I don’t like the solutions to field privacy. If we have proper DST, we need to add a nice way to call the destructor by-value (maybe add a `fn destroy<T: ?Sized>(t: *mut T)` that explicitly calls the drop-glue?)

---

<div class="post-metadata">

**Author:** ![tbu](https://avatars.discourse-cdn.com/v4/letter/t/839c29/32.png) [@tbu](https://internals.rust-lang.org/u/tbu)\
**Post date:** [April 8, 2015, 5:49pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/2 "2015-04-08T17:49:17Z")

</div>

Very nice, I’ve thought about this as well. In fact I’d go as far as actually replacing the `Drop` trait with that.

As for destructuring: I propose to change the destructuring rules so that you can only destructure if either

1. the struct is local to the module (important for `Drop` implementation) or
2. the struct does not possess private fields (important for the other use cases).

This means that you can take the object’s contents by value in the destructor and fixes the mess that is otherwise done with `mem::forget` and `ptr::read`.

---

<div class="post-metadata">

**Author:** ![tbu](https://avatars.discourse-cdn.com/v4/letter/t/839c29/32.png) [@tbu](https://internals.rust-lang.org/u/tbu)\
**Post date:** [April 8, 2015, 5:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/3 "2015-04-08T17:51:07Z")

</div>

Oh, and I propose that the Rust community takes a look at this before 1.0, because this really has the chance of fixing a few warts with the current destructor system.

---

<div class="post-metadata">

**Author:** ![aturon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aturon/32/3272_2.png) [@aturon](https://internals.rust-lang.org/u/aturon)\
**Post date:** [April 8, 2015, 6:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/4 "2015-04-08T18:10:00Z")

</div>

cc @pnkfelix @nikomatsakis

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [April 8, 2015, 8:22pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/5 "2015-04-08T20:22:30Z")

</div>

I am only still keeping `Drop` because of backwards-compatability. Edited to include your destructuring rules.

---

<div class="post-metadata">

**Author:** ![aidancully](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aidancully/32/5532_2.png) [@aidancully](https://internals.rust-lang.org/u/aidancully)\
**Post date:** [April 8, 2015, 8:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/6 "2015-04-08T20:58:36Z")

</div>

Is the idea that destructuring would prevent the `Destruct` glue from being invoked? Is there an idea that you could destructure enums that have `Destruct` glue? I guess the syntax for that would be something like:

```rust
match self { _ => () };

```

But that would [change current behavior](http://is.gd/LZNhvT). Is there an alternative syntax for enums that doesn’t rely on knowing each variant? ([This](http://is.gd/lXuCw6) would have the desired destructuring behavior, I think, but relies on knowing each available variant for the enum.)

FWIW, @eddyb also had an `Interior<T>` proposal which I probably won’t do justice to here, but which would allow an unsafe move from a value `T` into a value `Interior<T>`. `Interior<T>` does not implement `Drop`, so that by-value moves are allowed from `Interior<T>`. A `DropValue` trait(?) would take `Interior<T>` as an argument. This would work with enums that implement `Drop` very naturally.

[Previous discussion](http://internals.rust-lang.org/t/moves-from-self-during-the-drop-hook/1536).

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [April 8, 2015, 9:12pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/7 "2015-04-08T21:12:49Z")

</div>

This is irrellevant - a trivial match is a by-ref match and doesn’t consume the discriminant. Actually, trivial destructurings also behave this way in today’s Rust:

```
fn main() {
    let v = vec![4u32];
    let Vec { .. } = v;
    println!("{:?}", v); // No "use of moved value" error
}

```

If you want to consume the enum/struct, you need to make the match/destructuring by-value. Currently (e.g. [http://is.gd/SQIOOU](http://is.gd/SQIOOU)), rustc complains “cannot move out of type `Foo`, which defines the `Drop` trait”. I want this complaint to not be a problem with `Destroy`.

---

<div class="post-metadata">

**Author:** ![tbu](https://avatars.discourse-cdn.com/v4/letter/t/839c29/32.png) [@tbu](https://internals.rust-lang.org/u/tbu)\
**Post date:** [April 8, 2015, 9:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/8 "2015-04-08T21:41:03Z")

</div>

As for the requirement of destructuring in the destructor: We already have a (`#[deny]`) lint today that triggers if a method unconditionally recurses. I guess that would catch most of the errors about not destructuring `self` in `drop`.

---

<div class="post-metadata">

**Author:** ![aidancully](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aidancully/32/5532_2.png) [@aidancully](https://internals.rust-lang.org/u/aidancully)\
**Post date:** [April 8, 2015, 11:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/9 "2015-04-08T23:10:03Z")

</div>

> [@arielb1](#):
>
> a trivial match is a by-ref match and doesn't consume the discriminant. Actually, trivial destructurings also behave this way in today's Rust:

I probably wasn't clear enough, but I was trying to call that out as a possible problem: if we want the destruct hook to require a destructure to prevent an infinite recursion, then it'd be good if that destructuring could be ergonomic. There is also the issue of `Drop` impls on enums that don't easily get destructed:

```rust
enum Foo { Bar, Baz }
impl std::ops::Drop for Foo {
  fn drop(&mut self) {
    println!("drop");
  }
}

```

What does a consuming destructuring of this `Foo` look like? How do we make sure that we avoid a recursive drop loop for this enum type? `unsafe { std::mem::forget(self) }`?

---

<div class="post-metadata">

**Author:** ![pnkfelix](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pnkfelix/32/110_2.png) [@pnkfelix](https://internals.rust-lang.org/u/pnkfelix)\
**Post date:** [April 9, 2015, 7:23am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/10 "2015-04-09T07:23:27Z")

</div>

> [@tbu](#):
>
> Oh, and I propose that the Rust community takes a look at this before 1.0, because this really has the chance of fixing a few warts with the current destructor system.

I think when ideas like this [have been discussed in the past](http://internals.rust-lang.org/t/moves-from-self-during-the-drop-hook/1536), we've tended to try to identify if the ideas could be adopted post 1.0 -- that is, are they _compatible_ with the current `Drop` system. The principle being that we could have a smooth transition where we deprecate the `Drop` trait and transition to a new system like this one.

As far as I can tell, the proposal here falls into that category (since @arielb1 has stated that `Drop` remains solely for backwards-compatibility).

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [April 9, 2015, 9:48am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/11 "2015-04-09T09:48:16Z")

</div>

I think in this case you would have to use `std::mem::forget`. Actually, this applies to all cases where all members of `Self` are `Copy`, which _is_ slightly annoying. You could add a NoCopy marker, through.

---

<div class="post-metadata">

**Author:** ![aidancully](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aidancully/32/5532_2.png) [@aidancully](https://internals.rust-lang.org/u/aidancully)\
**Post date:** [April 10, 2015, 5:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/12 "2015-04-10T17:10:39Z")

</div>

Thanks, @arielb1, that’s how it seemed to me, too. I suppose an alternative would be to use a `move` keyword to mark a match as consuming (or possibly to override `Copy` semantics, and force a move?):

```rust
match move x { _ => () };

```

but difficulty in handling cases where a consuming destructuring isn’t easy is the main reason I stopped investigating this sort of mechanism when I looked at the problem.

---

<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:24am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-by-value-drop/1845/13 "2019-03-25T08:24:13Z")

</div>

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

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