# Pre-RFC: \`#\[must\_bind\]\`

**URL:** <https://internals.rust-lang.org/t/pre-rfc-must-bind/12658>\
**Category:** language design\
**Created:** [July 1, 2020, 8:42pm UTC](https://internals.rust-lang.org/t/pre-rfc-must-bind/12658 "2020-07-01T20:42:05Z")\
**Posts on this page:** 1\
**Showing post:** 25

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [July 9, 2020, 10:33am UTC](https://internals.rust-lang.org/t/pre-rfc-must-bind/12658/25 "2020-07-09T10:33:18Z")

</div>

> [@pickfire](#):
>
> I wonder why we have `let _ = foo()` to drop stuff directly rather than using `drop(foo())` .

To reiterate a point already made in this thread: `let _ = foo()` does _not_ “drop stuff directly”. It rather does “not bind” anything which may _result_ in dropping the value if it was only a temporary. The most natural way to think about `let _ = EXPR;` is: it’s _exactly_ the same as an `EXPR;` statement (and _not_ the same as `drop(EXPR)`) except for the fact that `let _ = EXPR;` suppresses `must_use` warnings.

The reason for _why_ `let _ = EXPR;` exists in the first place is rather for consistency since `_` is an irrefutable pattern (which is of course much more useful in a `match` statement) and `let` supports all other kinds of irrefutable patterns, too.

As to why `let _` and `let _a` must be different: That’s because patterns don’t need to move the value they match on but they can also just reference them: There’s `ref PAT` patterns and `ref mut PAT` patterns, so you can write something like

```rust
fn foo() {
    struct S{field: (bool,T)};
    impl Drop for S {
        fn drop(&mut self) {}
    }
    struct T;
    impl T {
        fn bar(&self) {
            println!("bar");
        }
    }
    let s = S{field: (false,T)};
    
    match s.field {
        (true, ref t) => t.bar(),
        _ => ()
    }
}

```

The `match` statement here inspects the field of `s` without trying to move it (which would be illegal since `S` implements `Drop`). Thus the pattern `_` cannot do any moving here. You want to always support a default-case with `_` in a match like the above and you want `{let PAT = EXPR; BODY}` to be same as `match EXPR { PAT => {BLOCK} }`, this the behavior of `let _`.

There could is a point to be made that `ref` patterns are just as confusing as `let _` and both should be forbidden in a change that makes `let` and `match` always move their value (unless it implements `Copy`, like when it’s a reference, and with an automatic re-borrow inserted for mutable references). In this case, we could now choose to either have matching against `_` behave like `drop` or like binding to some `_a`. `let _` would either be useless now (when it’s like `drop` -\> so we can disallow it and suggest to just use `drop`) or it wouldn’t be confusing anymore (if it binds to `_a`). But this isn’t going to happen anytime soon. One would also need to introduce an alternative mechanism for suppressing `must_use`, or, I suppose, one could use `drop` dropping `must_use` temporaries.

Huge language changes aside, something that we could probably do _right now_:

I’m not 100% sure on that, but wouldn’t `let _ = EXPR;` be the same as `EXPR;` in all the cases without a `must_use` warning, and the same as `drop(EXPR)` in all `must_use` cases? I suppose we could just add warnings against _every_ `let _ = EXPR;` and either suggest `EXPR;` or `drop(EXPR)` for replacement depending on whether a `must_use` warning would be generated. In my opinion, if I’m not missing anything, this would make a lot of code a lot clearer.

---

_[View the full topic](https://internals.rust-lang.org/t/pre-rfc-must-bind/12658)._
