True, good point. I still consider the example relevant – that is, if I saw that code, and it compiled, I would expect it to be mutating i
in place (but it wouldn’t be). I would find that surprising, given the “mental model” I described elsewhere (move
closures are “detached” from the stack frame’s local variables and have their own copy; normal closures are not).
If UnsafeCell<T>
were Copy
, as has been proposed, or we had a way to unsafe impl Copy
, then one could readily make an example where the change in behavior would be observed in an interesting way. As it is, hmm, I’m not sure if it can easily be done. (There’s no real reason that Cell
-like types can’t be copy, except that it would be such an easy footgun, more-or-less precisely for the reasons I’m showing here.)
I think the canonical example that made us not even try to infer “move” was something like this. It’s not quite the same scenario though:
let mut i = 1;
{
let x = || i += 1; // which `i` is mutated here?
x();
}
println!("{}", i);
More generally, I think that if the type of the variable being captured is “freeze” (i.e., no interior mutability, and hence truly immutable when shared), then I suppose that closures which use it will have the property that they never observe mutation from the outside (and hence making something move can only eliminate errors, precisely when such a mutation would be taking place).