# Lifetime in match if let and while let

**URL:** https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304
**Category:** Uncategorized
**Created:** [March 20, 2021, 11:51am UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304 "2021-03-20T11:51:38Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)
#### Post date: [March 20, 2021, 11:51am UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/1 "2021-03-20T11:51:38Z")

</div>

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

```rust

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?

---

<div class="post-metadata">

### Author: ![mbrubeck](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbrubeck/32/174_2.png) [@mbrubeck](https://internals.rust-lang.org/u/mbrubeck)
#### Post date: [March 20, 2021, 6:55pm UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/2 "2021-03-20T18:55:45Z")

</div>

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

> **[While let borrow lifetime seems to be too long](https://users.rust-lang.org/t/while-let-borrow-lifetime-seems-to-be-too-long/49784)**
>
> Hello, By my reasoning, the two while let -loop headers in the program below should be equivalent, but the commented-out one causes a panic, as the borrowed value is not dropped by the time control enters the loop body. Or am I missing something...

---

<div class="post-metadata">

### Author: ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)
#### Post date: [March 21, 2021, 9:23pm UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/3 "2021-03-21T21:23:23Z")

</div>

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):

```rust
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?

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [March 21, 2021, 10:02pm UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/4 "2021-03-21T22:02:47Z")

</div>

[There are cases where temporary lifetime extension is required for the code to compile, when you take a reference to a temporary](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=52380959bee33c51eb5ca668a6c8cbda). (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.

---

<div class="post-metadata">

### Author: ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)
#### Post date: [March 22, 2021, 4:03pm UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/5 "2021-03-22T16:03:36Z")

</div>

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...

---

<div class="post-metadata">

### Author: ![matthew-mcallister](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthew-mcallister/32/7105_2.png) [@matthew-mcallister](https://internals.rust-lang.org/u/matthew-mcallister)
#### Post date: [May 30, 2021, 5:29pm UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/6 "2021-05-30T17:29:31Z")

</div>

I just discovered this behavior yesterday and then [opened (and closed) an issue](https://github.com/rust-lang/rust/issues/85827). It's a genuine footgun, and it makes using both `Mutex` and `RefCell` slightly harder, as if they weren't hard enough!

Consider this snippet:

```rust
let x = RefCell::new(0i32);

// Panics
match x.borrow().is_negative() {
    _ => { *x.borrow_mut() = 0 },
}

// Succeeds
let tmp = x.borrow().is_negative();
match tmp {
    _ => { *x.borrow_mut() = 0 },
}

```

The former `match` statement panics while the latter does not, but I suspect very few Rust users would have guessed this outcome without already knowing the answer. It violates the substitution principle, which says that simply assigning to an intermediate variable should produce an equivalent program.

Lifetime extension is useful and works well when assigning a temporary reference to a variable, but the issue here is that `match` statements are activating lifetime extension _all the time_ and not just when necessary. Imagine we had this kind of desugaring going on:

```rust
// Before
match <expression> { ... }
// After
{
    let tmp = <expression>;
    match tmp { ... }
}

```

Then, the regular rules for activating lifetime extension would be used rather than having `match` statements be a weird exception where it's forced on at all times.

It's a breaking change, but I think if someone wants a temporary to live longer, they should be explicit about it and assign it to a variable instead of relying on a hard-to-discover rule.

---

<div class="post-metadata">

### Author: ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)
#### Post date: [August 28, 2021, 5:29pm UTC](https://internals.rust-lang.org/t/lifetime-in-match-if-let-and-while-let/14304/7 "2021-08-28T17:29:56Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
