SUPERSEDED:
The formal version of this RFC is up: RFC PR 238. The formal RFC supersedes this pre-RFC, and makes the other pre-RFC unnecessary.
Summary
Extend Rust’s mutability control semantics, so it also controls whether an object can be partially moved.
Motivation:
Currently, there is no way to restrain movability of Rust objects with move semantics - all movable objects can be moved at will. But it may be beneficial to have some control over movability, like how we have control over mutability.
EDIT: it is not correct to say that there is currently no way to restrain movability in Rust. For one, immutable objects do not accept "partial move-in"s. But they accept "partial move-out"s. This asymmetry is problematic. Becides, aren’t partial move-outs mutations?
This proposal is one of my two proposals on movability control (the other being that one). This one is intended to control the following kind of movability: the ability to partially move an object. Or, to solve the problem that “immutable” objects are not immutable enough.
In today’s Rust, it is valid to partially move an object in an immutable variable:
use std::mem::drop;
#[deriving(Show)]
enum Gender {
Male,
Female,
}
#[deriving(Show)]
struct Person {
pub name: String,
pub gender: Gender,
}
fn main() {
// Mike is stubborn that he will not change his name,
// or ever treat himself like a woman.
let mike = Person { name: "Mike".to_string(), gender: Male };
// However, we can erase his name without him noticing.
drop(mike.name);
// Now he is a nameless person, but he still has a gender.
println!("This nameless person is a {}.", mike.gender);
}
The above snippet compiles and runs, but it goes against intuition.
Detailed Design:
Definition:
- top-level object: a top-level object is the root of an object tree which inherits the top-level object’s mutability.
- there are two kinds of top-level objects, those stored directly in variables, and those stored directly in objects with internal mutability.
Add the following rules to Rust’s mutability semantics:
- if an object is immutable, then all its sub-objects with move semantics become immovable individually;
- if an object is mutable, then all its sub-objects with move semantics become movable individually;
- the movability of top-level objects is unconstrained, i.e. both immutable and mutable top-level objects can be moved as a whole.
(Note: Movability control of top-level objects is the subject of the other proposal.)
Thus, the above code snippet would cause a compile error on the drop call, telling us we cannot partially move an immutable object.
Drawbacks:
- breaking change;
- increased implementation complexity.
Alternatives:
Maintain the status quo.
The status quo may be fine, as once an object gets partially moved, it’s a compile error to use the moved parts or the object as a whole, so partial moves of immutable objects may not be a serious problem.
Still, the fact that we can move away parts of an “immutable” object and render it unusable is quite against the definition of “immutable”, and we’d better have less surprise in the language.
EDIT: And the scoped lifetime guarantee in the other proposal requires guaranteed partial-immovability. This is another point for the change.
Unsolved Questions:
None that I am aware of.