# A move semantics centric view of drops (Addressing problems of RFC PR 210, Take 3)

**URL:** <https://internals.rust-lang.org/t/a-move-semantics-centric-view-of-drops-addressing-problems-of-rfc-pr-210-take-3/448>\
**Category:** ideas (deprecated)\
**Created:** [August 30, 2014, 1:41pm UTC](https://internals.rust-lang.org/t/a-move-semantics-centric-view-of-drops-addressing-problems-of-rfc-pr-210-take-3/448 "2014-08-30T13:41:01Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![CloudiDust](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cloudidust/32/197_2.png) [@CloudiDust](https://internals.rust-lang.org/u/CloudiDust)\
**Post date:** [August 30, 2014, 1:41pm UTC](https://internals.rust-lang.org/t/a-move-semantics-centric-view-of-drops-addressing-problems-of-rfc-pr-210-take-3/448/1 "2014-08-30T13:41:01Z")

</div>

Old title: A lifetime-management centric view of drops. I think the new one fits the contents better.

* * *

When I was preparing the RFC (which never sees the light of the day) for the `~` early drop point marker, I gave some thought into what implicit drops really mean, and realized:

Early drops are _measures_, not _problems_.

They are measures for balancing object moves in different branches of execution.

This is a very important matter of perspective.

## A matter of perspective

C++'s move semantics is bolted on, just like many other things there. In particular, move semantics there is constrained by its _implicit destructor invoking semantics_. And what we call _drop flags_, is originally a way to walk around C++'s limitation. It’s just that in C++, drop flags is a convention which must be implemented by the programmer manually, while in Rust, it is automatically handled by the compiler.

But Rust doesn’t _have to_ inherit this limitation. Rust is a clean slate _centred around_ ownership and lifetime management, so it is natural to think about drops, or anything for that matter, in this context.

## It’s all about lifetime management

What is _ownership_?

- The ability to control an object’s lifetime.

What is a _move_?

- An action to give up/transfer ownership.
- The target is said to _consume_ the object.

What is a _drop_?

- A special move - into oblivion.

What can the owner of an object do?

1. maintain ownership - do nothing, or pass the object by reference;
2. explicitly transfer ownership - call consuming functions, including `drop`, or do _move by assignment_;
3. implicitly give up ownership - the compiler inserts implicit drop calls.

## The move guarantees and implicit drops

What Rust currently provides, the so called _dynamic drop semantics_, actually satisfies the following guarantee:

**Emptied Scope Guarantee**.

- At the end of a scope, all movable objects owned by the scope are guaranteed to have been moved out of the scope.

And, the _implicit drops at the end of scopes_, or _implicit scoping drops_ as I now call them, are drops we are all familiar with. They are measures the compiler takes to satisfy this guarantee.

The Rust compiler’s reasoning, from this point of view, is as follows:

1. All owned objects must be moved out.
2. But the programmer doesn’t explicitly move some of them.
3. Implicit moves needed.
4. But where to?
5. The only destination that I can think of without the programmer’s explicit instruction, is _oblivion_.
6. So, I should insert implicit drops.

Well we can see, implicit drops already exist in Rust, and they are measures to satisfy a guarantee, not disasters waiting to happen.

The above also applies to the so-called _static drop semantics_ and _early drops_.

“Wait! But implicit scoping drops don’t cause problems!”

Eh, no. Consider:

```
fn fancy() {
    let foo = ...
    ...
    consume(foo); // important, must call!
    ...
}

```

What happens when you forget the `consume` call? You lose `foo` to oblivion. If instead you are required to explicitly call `drop(foo)` at the end of the scope, maybe it’ll be easier for you to remember to call `consume`?

So, just like sometimes you do not want early drops, sometimes you do not want the “not-early” drops too. They are not as different as you may think.

“OK, then what?”

So, what exactly is _static drop semantics_? What exactly are _early drops_?

Or, as I’d like to say, the _balanced move semantics_ and _implicit balancing drops_.

_Balanced move semantics_ also satisfies the _Emptied Scope Guarantee_. Additionally, with the help of _implicit balancing drops_, it satisfies:

**Balanced Move Guarantee**

- All branches of the same branching operation are guaranteed to move the same set of objects.

Yeah, simple like that.

## The “problems”

“Well, from this new perspective, the new semantics is indeed simple, but it is still different to how C++ works so …”

**Balanced moves makes code reasoning harder.**

Nope, I’d argue that it actually makes code reasoning easier, if you know the additional guarantee.

With dynamic drops, you cannot just look at an object somewhere in the code and statically determine whether it is alive or not, because its liveness is decided by the code path that get executed at runtime. But with balanced move semantics, you can do this.

“But if I look at a single code path, it may drop something completely unrelated.”

Question, does this matter?

No? Then why bother?

Yes? Then you are worried that this code path may be dropping something you care about.

The only reason this path may be implicitly dropping it, is that it get moved in another path.

Do you move it in another path?

Of course you know, because you care, right?

Anyway, balanced moves effectively “forces” the programmer to get the big picture. I think this is a good thing in the long run.

**Balanced moves make it harder to ensure that an object has scoped lifetime.**

Eh, no again. The only way to ensure that an object has scoped lifetime is ensuring that _it never moves out of the scope before the end of the scope_. If you want scoped lifetime, then surly you _will_ not explicitly moving it.

- If you are not explicitly moving it in branches, the balanced move guarantee would guarantee that it would not get moved/dropped in any branches.
- If you are explicitly moving it in one branch but not others, then you _already give up control_ in that one branch, and anything can threaten the object’s life. You are already doing it wrong _today_, balanced move semantics or not, irrelevant.

So this leads us to the big question …

## What new problems does `NoisyDrop`/`QuietDrop` solve

I don’t know.

As I said above, balanced moves doesn’t introduce new problems, if anything, they may _highlight_ existing ones.

## What do we actually need

1. Change the perspective we think about drops. Don’t get limited by the C++ mentality.
2. A way to directly tell the compiler that we want guaranteed scoped lifetime on some objects.

As I said, the only way to ensure that an object has scoped lifetime is ensuring that _it never moves out of the scope before the end of the scope_.

So what we need is simply an attribute `#[lifetime(scope)]` on objects. Once an object get tagged, it can never leave the scope.

_And we can have use for this attribute today!_

---

<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:22am UTC](https://internals.rust-lang.org/t/a-move-semantics-centric-view-of-drops-addressing-problems-of-rfc-pr-210-take-3/448/2 "2019-03-25T08:22:50Z")

</div>

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

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