Modifying a moved field


#1

Hello!

Why am I allowed to do this?:

I assume the Foo struct has been shallow copied so I can overwrite the contents in the stack without a segfault, but I thought the ownership had moved and that rustc would stop me from doing this.

Cheers,

Phil


#2

if you try to use the move value, for example printing f.name, then it will not work.

I guess because you can not ‘use’ the moved value, so its not like it matters that you can change the field?


#3

This seems nonsensical to me. There’s no utility to being able to assign a field of a moved value, and it certainly doesn’t do what a casual reader would think it does.


#4

I agree, this should be disallowed.


#5

I thought this would actually “re-validate” the structure and allow you to use it again, but it doesn’t, so this seems like a borrowck bug.


#6

In general moves are tracked at a pretty narrow level of granularity. We intend to eventually permit you to “fill” both fields back in and then use the structure again. I guess that doesn’t work today. I have to go look again at the moves code, but I think in general one of the things I’d like to pursue post 1.0 is extending the type system to deal better with things that have been moved from (in particular I want to support moves out of &mut pointers, so long as you restore the value before doing anything fallible). Anyway I think this example more-or-less falls out of treating things in a general way, though you could imagine rules that say “if you move f, you can never again touch any subfields of f without restoring f as a unit”.


#7

> In general moves are tracked at a pretty narrow level of granularity.

That makes sense, and it would make closures a lot nicer (rather than individually borrowing members of a struct), but I notice it doesn’t seem to work that way right now:

#[deriving(Show)]

struct Bar;

struct Foo {

pub foo: Bar,

pub bar: Bar,

}

fn main() {

let mut x = Foo { foo: Bar, bar: Bar };

let c = || {

x.foo = Bar;

};

println!("{}", x.bar); // error: cannot borrow x.bar as immutable because x is also borrowed as mutable

}

> you could imagine rules that say “if you move f, you can never again touch any subfields of f w ithout restoring f as a unit”.

I like this as a nice middle ground. Restoring the individual fields of f seems error prone and difficult to read - I’d be very inclined to have the definition of the struct open in another tab, just to make sure all the fields really are being restored. Restoring as a unit makes sure it all happens in one sane place, and helps assure the reader that all the fields really are restored at that point.


#8

Oops, sorry, aside from the broken code sample, @cgaebel showed me that move closures totally do this.


#9

That is correct, closures always borrow (or move) the variables they touch. This may change in the future. This is separate from the tracking within a single fn body, however, which is done at a finer level of granularity.


#10

Actually, that surprises me. I’ll have to look again, but I thought we always modeled closure captures at the variable level at the moment, not subpaths.