Experimenting with the programming language Rust, I found that the compiler is able to track a move of a field of some struct on the stack very accurately (it knows exactly what field has moved).
However, when I put one part of the structure into a Box
(i.e. putting it onto the heap), the compiler is no longer able to determine field-level moves for everything that happens after the dereference of the box. It will assume that the whole structure "inside the box" has moved. Let's first see an example where everything is on the stack:
struct OuterContainer {
inner: InnerContainer
}
struct InnerContainer {
val_a: ValContainer,
val_b: ValContainer
}
struct ValContainer {
i: i32
}
fn main() {
// Note that the whole structure lives on the stack.
let structure = OuterContainer {
inner: InnerContainer {
val_a: ValContainer { i: 42 },
val_b: ValContainer { i: 100 }
}
};
// Move just one field (val_a) of the inner container.
let move_me = structure.inner.val_a;
// We can still borrow the other field (val_b).
let borrow_me = &structure.inner.val_b;
}
And now the same example but with one minor change: We put the InnerContainer
into a box (Box<InnerContainer>
).
struct OuterContainer {
inner: Box<InnerContainer>
}
struct InnerContainer {
val_a: ValContainer,
val_b: ValContainer
}
struct ValContainer {
i: i32
}
fn main() {
// Note that the whole structure lives on the stack.
let structure = OuterContainer {
inner: Box::new(InnerContainer {
val_a: ValContainer { i: 42 },
val_b: ValContainer { i: 100 }
})
};
// Move just one field (val_a) of the inner container.
// Note that now, the inner container lives on the heap.
let move_me = structure.inner.val_a;
// We can no longer borrow the other field (val_b).
let borrow_me = &structure.inner.val_b; // error: "value used after move"
}
I suspect that it has something to do with the nature of the stack vs. the nature of the heap, where the former is static (per stack frame at least), and the latter is dynamic. Maybe the compiler needs to play it safe because of some reason I cannot articulate/identify well enough.
ValContainer
), not on the contained integer. And custom struct types are by default notCopy
able, to my knowledge. – Enterostomy