# Another take on \`ImplictDrop\`

**URL:** <https://internals.rust-lang.org/t/another-take-on-implictdrop/15831>\
**Category:** language design\
**Created:** [December 21, 2021, 1:02pm UTC](https://internals.rust-lang.org/t/another-take-on-implictdrop/15831 "2021-12-21T13:02:00Z")\
**Posts on this page:** 4\
**Page:** 1

<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:** [December 21, 2021, 1:02pm UTC](https://internals.rust-lang.org/t/another-take-on-implictdrop/15831/1 "2021-12-21T13:02:00Z")

</div>

- Feature Name: `implicit_drop`
- Start Date: 2021-07-22
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary

A trait for types whose values may not be dropped automatically and therefore require additional attention.

# Motivation

- Additional of this trait allows library authors to force users to think about concrete uses of certain values they are provided with.
- The intension is to add absolutely minimal support for linear types.
- Make working with such values not too complicated via mechanism.

# Guide-level explanation

The trait is defined as follows:

```rust
pub auto trait ImplicitDrop {}

```

This is an auto trait, built in into the language.

It is implied bound for all generic parameters, like `Sized`.

The syntax which is used to opt out from it is following: `?ImplicitDrop`.

The trait is here to allow types to require explicit disposing and thus making code more readable and safe.

Essentially this is hard `#[must_use]` lint on the type level. Supposed to be used in cases where accidental drop of a value may cause undesired behavior.

Example:

```rust
enum TransactionState {
  Clean,
  InProgress,
}

struct TransactionGuard<`c,const STATE: TransactionState>
{..}

impl<`c> !ImplicitDrop for TransactionGuard<`c,{TransactionState::InProgress}> {};

fn example() {
  //...
  let mut handle = handle.begin(); // yields "transaction in progress type";
  match data {
    Some(data) => {
      //...
      handle.commit(); //value consumed, all is ok.
    },
    None => {
      //...but here we also have to finalize transaction
      // if we comment the next line the code will fail to compile
      handle.abort();
    }
  }
}

```

Note, the trait on its own has nothing to do with finalization, etc. This means that desired ways of consuming value are determined separately, and most probably going to depend on concrete contexts, etc.

## Finalizer methods

New attribute `#[finalize]` is introduced. It marks a method as final destination of a value. It requires an implementor type to be `Drop` and annotated method to take `self` by value. `Drop` type are allowed to be destructed only inside `#[finalize]` methods. These methods can have return types.

```rust
impl<`c> TransactionGuard<`c,TransactionState::InProgress> {
  #[finalize]
  fn commit(self) -> Result<(),Error> {...};

  #[finalize]
  fn abort(self) {...};
}

```

Important detail is that if finalizer methods is not in scope (and not inherent), it's not required to be called, instead `drop` is considered as the least possible finalization method. The main reason of doing so is that we don't run in scoping problems and avoid concerns about _ **the default finalization way** _.

# Reference-level explanation

```rust
pub auto trait ImplicitDrop {}

```

The opt out bound `?ImplicitDrop` disables calling a destructor on leaving a scope for values of some bound type. Such value going out of scope results in an error.

So the following will not compile:

```rust
fn impl_show<T: ?ImplicitDrop>(arg: T) {
  say_hello();
  //error: cannot implicitly drop function's argument
  //suggestion: add `drop(arg);`
}

```

The reason of doing the trait in such way is that this will require no changes in existing code:

- All types in the language will automatically get it implemented;
- It's opt-out bound like `Sized`.
- It requires adding support for such types on per container basis. But in most cases one is already calling `drop` (or `drop_in_place`) manually, or adding such a support is one line level change (thanks to `drop`).

## Finalization

We add `#[finalize]` attribute for methods.

It allows to destructure the type regardless of whether it implements `Drop` or not.

Using this attribute implies and requires `Self` to be `!ImplicitDrop`.

## Implementation

There are two approaches on how to implement this:

1. We compile code as usual, but when MIR tries to insert `drop` call for a `!ImplicitDrop` value we error out.
2. We do CFG (dataflow) analysis, during it we determine which values go out of scope and check whether we can implicitly drop any.

# Drawbacks

The worst thing about this proposal is that it requires library support for `!ImplicitDrop` types.

# Rationale and alternatives

- I've considered other variants for finalization: however, making `#[finalize]` to actually implement a trait leads to:
  - Need to include these traits in prelude =\> edition
  - `Fn`-like traits =\> burden

- Also, there are multiple approaches to adding linear types:
  - Make `T: Drop` to actually make some sense =\> not backward compatible
  - `Forget` auto-trait on its own =\> only opens a way for linear types, but doesn't assist in using them.

# Prior art

- [`Forget` auto trait](https://internals.rust-lang.org/t/pre-rfc-add-forget-auto-trait-again/15807)

- [Gankra's linear rust](https://gankra.github.io/blah/linear-rust/)

# Unresolved questions

- The merit of the proposal.

---

<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 21, 2021, 1:56pm UTC](https://internals.rust-lang.org/t/another-take-on-implictdrop/15831/2 "2021-12-21T13:56:50Z")

</div>

Is a struct containing a `!ImplicitDrop` field automatically `!ImplicitDrop`?

---

<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:** [December 21, 2021, 2:10pm UTC](https://internals.rust-lang.org/t/another-take-on-implictdrop/15831/3 "2021-12-21T14:10:30Z")

</div>

Yes, it's an auto-trait

---

<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 21, 2022, 2:11pm UTC](https://internals.rust-lang.org/t/another-take-on-implictdrop/15831/4 "2022-03-21T14:11:27Z")

</div>

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