# Pre-RFC: Move references

**URL:** <https://internals.rust-lang.org/t/pre-rfc-move-references/14511>\
**Category:** language design\
**Created:** [April 17, 2021, 2:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-move-references/14511 "2021-04-17T14:58:11Z")\
**Posts on this page:** 1\
**Showing post:** 30

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [April 19, 2021, 3:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-move-references/14511/30 "2021-04-19T15:01:43Z")

</div>

If `&move in T` worked just like an uninitialized local `let x: T;`, it would be an error to capture it in a closure, move it into a struct, or pass it to a function expecting some U by value. The requirement to initialize could mean that any (non-panic) returns from the function count as a use of the initialized value, so the `&move in` must have either been directly initialized or passed to some other function. After doing either, it could be used normally as a `&mut`.

For unsafe code you'd need to be able to borrow it as a `&mut MaybeUninit<T>` or take a raw pointer, and there would have to be something like a function `fn assume_init<T: ?Sized>(x: &move in T)`, which would be found somewhere behind many non-trivial uses.

When unwinding from a function taking some `&move in`, it should be considered uninitialized. Any other `&move in` references that are in scope are either initialized or not (known statically or via drop flags), and should be dropped if they are.

```rust
impl<T> Box<T> {
    fn new_with(f: impl Fn(&move in T)) {
        let b = Box::new_uninit();
        let move_in_ref = b.placeholder_into_move_in(); // &mut MaybeUninit<T> -> &move in

        f(move_in_ref);

        // Safety:
        // *move_in_ref is initialized here, meaning that so is the box it came from
        unsafe { b.assume_init() }
    }
}

fn main() {
    // OK
    let x = Box::new_with(|x_ref| { *x_ref = 42; });
    // ERROR: x_ref must be initialized before returning
    let x = Box::new_with(|x_ref| { });
}

```

At this point it looks more like a different style of parameter than a proper type. I don't know if the limitations leave it sufficient power. For example, a function initializing only some prefix of a slice would want to (and have to!) return the remaining uninitialized part to the caller, but to do that in a usable way it would have to be part of some tuple or Result, which goes outside of what uninitialized locals can currently do.

Maybe `&move in` references could be moved into structs or enums if those compound values were then infected by the same restrictions. However, not being able to pass to a generic function is not so simple once the reference is hidden in a Result or such. Some form of proper linear types along the lines of [Pre-RFC: Leave auto-trait for reliable destruction](https://internals.rust-lang.org/t/pre-rfc-leave-auto-trait-for-reliable-destruction/13825) would seem to be needed.

A more complex example that would require returning tuples of `&move in`:

```rust
// initialize a slice by recursively initializing both halves
fn recursive(v: &move in [String], mut s: String) {
    // this would need some new API since [T]::len takes &[T]
    let len = v.len();
    match v {
        [] => (),
        [x] => {
            if rare_error() { 
                panic!("oops")
            }
            *x = s;
        }
        v => {
            // this can't work with the above limitations,
            // since how would the function create the tuple to return
            let (head,tail) = v.split_at_movein(len/2); 

            let mut s2 = s.clone();
            s.push_str("0");
            // panic from this call would drop only s2
            recursive(head, s);
            s2.push_str("1");
            // panic from this call would drop only head
            recursive(tail, s2);  
        }
    }
}
let x = Box::<[String;4]>::new_with(|v| {
    recursive(v as &move in [String], String::new())
});
assert_eq(*x, ["00","01","10","11"]);

```

---

_[View the full topic](https://internals.rust-lang.org/t/pre-rfc-move-references/14511)._
