# \[Pre-RFC\] Allow moves on objects with active borrows

**URL:** <https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907>\
**Category:** language design\
**Created:** [August 22, 2016, 9:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907 "2016-08-22T21:14:33Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![MaikKlein](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/maikklein/32/2570_2.png) [@MaikKlein](https://internals.rust-lang.org/u/MaikKlein)\
**Post date:** [August 22, 2016, 9:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/1 "2016-08-22T21:14:33Z")

</div>

#Motivation

```
struct Foo<'r> {
    i: Box<Baz>,
    b: Bar<'r>,
}
struct Baz;

struct Bar<'r> {
    i: &'r Baz,
}

let boxed_baz = Box::new(Baz{});
let boxed_ref: &Baz = boxed_baz.as_ref();
let f = Foo{i: boxed_baz, b: Bar{i: boxed_ref}};

```

Which results in:

```
error[E0505]: cannot move out of `boxed_baz` because it is borrowed
  --> src/main.rs:51:20
   |
50 | let boxed_ref: &Baz = boxed_baz.as_ref();
   | --------- borrow of `boxed_baz` occurs here
51 | let f = Foo{i: boxed_baz, b: Bar{i: boxed_ref}};
   | ^^^^^^^^^ move out of `boxed_baz` occurs here

```

A more real example would look like this

```
struct Device;

struct CommandBuffer {
    device: &Device,
    // ...
}

// Does not work because Rust does not allow internal pointers
struct Something {
    device: Device,
    command_buffer: CommandBuffer,
}

```

The workaround for this problem is to fallback to [Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html)

```
struct Device;

struct CommandBuffer {
    device: Arc<Device>,
    // ...
}

struct Something {
    device: Arc<Device>,
    command_buffer: CommandBuffer,
}

```

[Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) imposes the following drawback

- Atomic counter
- Ignores Rust’s lifetime system

#Solution

Add a builtin trait to allow moves even with active borrows.

`unsafe impl<T> BorrowMove<&T> for Box<T> {}`

If Rust encounters a borrow of type `&T` that is linked to a `Box<T>`, it will allow the box to be moved to a equal or larger lifetime.

Rust will still refuse to move `Box<T>` for every other active borrow, this includes `&Box<T>`.

#Problems

Unsure how this will interact with custom alloactors.

#Closing thoughts

This is not really a well crated _RFC_. I encountered the problem recently while designing vulkan wrapper.

The proposed solution is probably too optmistic and will have some problems. The main goal for the **pre** -rfc is to see if moving should be allowed for some types that have active borrows.

---

<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:** [August 22, 2016, 9:48pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/2 "2016-08-22T21:48:21Z")

</div>

How does that not create a dangling pointer?

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [August 22, 2016, 10:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/3 "2016-08-22T22:00:53Z")

</div>

The `Box`'s heap pointer shouldn’t be affected by moving the `Box` itself, so there’s no real dangling.

---

<div class="post-metadata">

**Author:** ![DanielKeep](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/danielkeep/32/1332_2.png) [@DanielKeep](https://internals.rust-lang.org/u/DanielKeep)\
**Post date:** [August 23, 2016, 2:51am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/4 "2016-08-23T02:51:31Z")

</div>

```rust
let a = Box::new(0);
let b = &a;
let c = ('x', a, 'x');
let d = **b;

```

Unless you’re going to actually teach Rust the difference between borrowing a thing and a borrow of a thing owned (but not contained in) a thing, this is never going to work.

---

<div class="post-metadata">

**Author:** ![hanna-kruppe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hanna-kruppe/32/6540_2.png) [@hanna-kruppe](https://internals.rust-lang.org/u/hanna-kruppe)\
**Post date:** [August 23, 2016, 7:19am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/5 "2016-08-23T07:19:28Z")

</div>

If arbitrary moves of the `Box` are permitted, then so is this:

```rust
let b = Box::new(..);
let r = &*b;
drop(b):

```

Additionally, since presumably one still needs mutable access to _at least_ the Box itself, if not its contents since otherwise a type containing a Box becomes effectively immutable (or needs to fall back to pervasive interior mutability). Leaving aside the question of how one can restrict “derived” borrows, this too can lead to dangling pointers, e.g.:

```rust
// structs as above

let boxed_baz = Box::new(Baz{});
let boxed_ref: &Baz = boxed_baz.as_ref();
let f = Foo{i: boxed_baz, b: Bar{i: boxed_ref}};
 // write a new boxed Baz to f.i, drop the old one
::std::mem::replace(&mut f.i, Box::new(Baz{}));

```

---

<div class="post-metadata">

**Author:** ![MaikKlein](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/maikklein/32/2570_2.png) [@MaikKlein](https://internals.rust-lang.org/u/MaikKlein)\
**Post date:** [August 24, 2016, 10:12am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/6 "2016-08-24T10:12:53Z")

</div>

Yeah that seems to be a problem that I haven’t thought about.

In general the move onto the stack can’t be allowed. Allow to move `Box<T> to Box<T>`, but disallow a move to something else like `Box<T>` to `T`.

This should probably also be user specified.

---

<div class="post-metadata">

**Author:** ![dan\_t](https://avatars.discourse-cdn.com/v4/letter/d/eada6e/32.png) [@dan\_t](https://internals.rust-lang.org/u/dan_t)\
**Post date:** [August 24, 2016, 10:41am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/7 "2016-08-24T10:41:01Z")

</div>

> [@MaikKlein](#):
>
> In general the move onto the stack can't be allowed. Allow to move Box\<T\> to Box\<T\>, but disallow a move to something else like Box\<T\> to T.

This will only work if Box doesn't contain any other field than the heap pointer - which seems to be case by looking into the implementation - but to know this difference you have to look deeply into the implementation, so this kind of borrowing seems like a bad idea, because most likely the user will not have this deep knowledge and will have a hard time to understand why it works sometimes and in other cases not.

The other thing is, that this might introduce breaking changes to user code if the author of a library adds a private field and suddenly the user can't borrow the struct in the same way as before.

For some people borrowing is now already too much to bother with, so making the whole system even harder to comprehend IMHO won't help.

---

<div class="post-metadata">

**Author:** ![DanielKeep](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/danielkeep/32/1332_2.png) [@DanielKeep](https://internals.rust-lang.org/u/DanielKeep)\
**Post date:** [August 24, 2016, 12:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/8 "2016-08-24T12:10:24Z")

</div>

I think you’ve misunderstood. I’m not moving the contents of the box, _I’m moving the box._`&a` is a pointer to the `Box` on the stack, then using the proposed change, I move the `Box` itself to somewhere _else_ on the stack, then dereference the `Box` (which is no longer where the pointer is pointing).

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [August 24, 2016, 8:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/9 "2016-08-24T20:03:27Z")

</div>

This is one of the main challenges with today’s borrow system. There are a number of challenges with integrating support for this feature into Rust today. One of the biggest is something that your proposal hinted at: in order for this to be even remotely safe, we need to know that the data was borrowed from something with a stable address. So e.g. if you borrow the interior of a `box`, then even if we move the box, that address won’t change. But this is not true for many containers, because they store things internally (e.g., `Option`). For other containers, like `Vec`, it is parly true. One can imagine adding some kind of traits to try and express that (e.g.) the “deref of this ptr type is stable”, which seems to be what you are proposing.

But another big problem is that the borrow checker just doesn’t track information in the way that you propose. For example, if I do `let x = &foo.bar`, the borrow checker records two independent facts: (1), that the reference `x` has lifetime `'x`, and (2) that `foo.bar` is borrowed for the lifetime `'x`. You can see that these facts are linked (both reference the lifetime `'x`), but there is no direct path from the reference `x` to the fact that it is derived from `foo.bar`. There may in fact be _many_ references with lifetime `'x`, so there is no 1-to-1 correlation between them. This means that we can’t (for example) determine that when `foo.bar` is moved, `x` remains alive – at least not without a deep change to the borrow checker.

(There are some other challenges – some of which were highlighted by others on this thread – but I’ll leave it at that for now. =)

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [August 24, 2016, 8:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/10 "2016-08-24T20:06:02Z")

</div>

Well, ok, I won't leave it at that. To reiterate what @hanna-kruppe wrote:

> [@hanna-kruppe](#):
>
> If arbitrary moves of the Box are permitted, then so is this:

Right now, if I have some fn like `fn foo(x: Box<T>)`, I know that `x` and all data owned by `x` are unaliased. Lots of code and patterns rely on this. So if we are going to allow some borrows to outlast a move, we have to still forbid calling `foo` with an outstanding borrow (as `foo` is within its rights to free `x` or move it to another thread).

---

<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:26am UTC](https://internals.rust-lang.org/t/pre-rfc-allow-moves-on-objects-with-active-borrows/3907/11 "2019-03-25T08:26:43Z")

</div>

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