Lifetime in match if let and while let

I am very surprising found that, a temp variable only drop AFTER a WHOLE sentences is executed.


fn dead_lock_2() {// originally published in a Chinese forum https://rustcc.cn/article?id=3f446fab-1f4b-4d3f-9240-95b673bf5062
    let vec_mutex = Mutex::new(vec![1,2,3]);
    while let Some(num) = { vec_mutex.lock().unwrap().pop() } {
        if num == 2 {
            vec_mutex.lock().unwrap().push(4);// could not acquire the lock since `vec_mutex.lock()` in while expr is not dropped.
        }
        println!("got {}", num);
    }
}

I am very surprising to find that, many problem (include this one) could be solved by changing the expr to (||expr)() or {let tmp=expr;tmp}--most of the cases, we do not need a &, or a &mut I am really curious about that, why the default setting is drop the temp variables after an expression is executed, and why the behavior of (||expr)() or {let tmp=expr;tmp} could not be the default setting.

is it always better using (||expr)() or {let tmp=expr;tmp} than expr? if not, could anyone provide me a example?

If {let tmp=expr;tmp} always compiles when expr compiles, why not using the behavior of {let tmp=expr;tmp} instead of the old one?

There are some links and discussion about this on the users forum, here:

1 Like

Thank you for your useful link.

that link suggests a better way dealing with if-let / while-let / match (just as what I want to do):

while let Some(x)={let tmp=expr.calling_some_method_that_create_temporary_variables;tmp}{
    ...
}

But, both the reply and relative link do not show when {let tmp=expr.calling_some_method_that_create_temporary_variables;tmp} fails to compile but a single expr.calling_some_method_that_create_temporary_variables compiles.

If {let tmp=expr.calling_some_method_that_create_temporary_variables;tmp} is always better, why not rust using this behavior in the next version?

There are cases where temporary lifetime extension is required for the code to compile, when you take a reference to a temporary. (Playground link)

Almost more importantly, it changes the drop timing, and the drop timing is observable in many ways. Consider a type that changes some global atomic on Drop. Changing the drop timing would change the result of your code.

At the most extreme, consider that the temporary holds some lock, releases it on drop, and you have some unsafe code that assumes that the lock is held. Changing the drop timing would thus silently make this code UB which was valid before.

3 Likes

Heh. Last week I was trying to puzzle out the interaction of this rule with the drop order of lazy boolean expressions w/ @Manishearth. I think he filed a bug against the reference because of confusing text, and I wonder if this is worth clarifying, too...

1 Like