# Allow the infinite \`loop\` keyword to prefix expressions w/ blocks

**URL:** <https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633>\
**Category:** language design\
**Created:** [April 9, 2024, 11:06pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633 "2024-04-09T23:06:22Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [April 9, 2024, 11:06pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/1 "2024-04-09T23:06:22Z")

</div>

Change the syntax of [InfiniteLoopExpression](https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops) from "`loop` _BlockExpression_" to "`loop` [_ExpressionWithBlock_](https://doc.rust-lang.org/reference/expressions.html)", excluding _LoopExpression_.

In addition, if the control flow of the inner expression is not exhaustive, a default case should be appended that breaks out of the loop automatically.

This would allow for the following constructs:

- `loop match` / `loop` [_MatchExpression_](https://doc.rust-lang.org/reference/expressions/match-expr.html)

- `loop if` / `loop` [_IfExpression_](https://doc.rust-lang.org/reference/expressions/if-expr.html#if-expressions)

- `loop if let` / `loop` [_IfLetExpression_](https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions)

- `loop unsafe` / `loop` [_UnsafeBlockExpression_](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks)

In addition, this syntax would help reduce excessive indentation; a.k.a. "rightward drift".

Related discussions:

- [Pre-RFC: loop/for/else match](https://internals.rust-lang.org/t/pre-rfc-loop-for-else-match/930)

- [Loop-match, for-match](https://internals.rust-lang.org/t/loop-match-for-match/13867)

- [Eliminating "seemingly unnecessary" braces](https://internals.rust-lang.org/t/eliminating-seemingly-unnecessary-braces/12971)

---

<div class="post-metadata">

**Author:** ![eggyal](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eggyal/32/7947_2.png) [@eggyal](https://internals.rust-lang.org/u/eggyal)\
**Post date:** [April 10, 2024, 12:16am UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/2 "2024-04-10T00:16:21Z")

</div>

Given that you've found those relevant previous discussions, have you any thoughts on the counterarguments that were raised within them?

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [April 10, 2024, 12:19am UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/3 "2024-04-10T00:19:16Z")

</div>

> [@Yokin](#):
>
> A potential downside is that the `else` case could be confused for a final exception case that runs after the loop ends.

Or that runs if the loop never runs -- other languages do have that construct, so the potential seems high to me.

---

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [April 10, 2024, 12:49am UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/4 "2024-04-10T00:49:02Z")

</div>

All of the related discussions propose a `loop match`, but they all go overboard with entirely new disparate syntax (like `for match x in iter` or endless unbracketed keyword chaining). They mostly just debate that other syntax.

They also generally define `loop match` as syntax sugar for `loop { match .. }`, which people either seem okay with as a convenience, or dislike it for being unnecessary. However, I think the addition of the implicit `break` as a default case of fallible control flow is a big difference with my proposal that makes it hold more water as a unique utility.

---

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [April 10, 2024, 12:56am UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/5 "2024-04-10T00:56:51Z")

</div>

I would almost want to make `loop if {..} else ..` invalid syntax, but I feel like having exceptions to the general rule is awkward or unintuitive in its own way. I'm unsure if there's a good rule for it that wouldn't seem ambiguous. Maybe just `loop match` on its own would be better.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 10, 2024, 7:58am UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/6 "2024-04-10T07:58:09Z")

</div>

> [@Yokin](#):
>
> I would almost want to make `loop if {..} else ..` invalid syntax, but I feel like having exceptions to the general rule is awkward or unintuitive in its own way.

This is my thought -- but about `loop match` and such too.

"Yes, it needs braces. If you have so many nested `loop`s that the indentation is high, make a function" seems like an entirely reasonable answer to me. Otherwise there's a huge trail of "but I want `else loop`" and such where all the same motivations hold, and I'd rather just do none of them.

---

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [April 10, 2024, 5:15pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/7 "2024-04-10T17:15:18Z")

</div>

Yeah I think at that point it should just be a macro with the same functionality. The syntax `loop x {}` seems very natural and convenient, but it seems like a bad fit for Rust after thinking about it more. I'll leave the post up for posterity or any further discussion.

---

<div class="post-metadata">

**Author:** ![idanarye](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/idanarye/32/3346_2.png) [@idanarye](https://internals.rust-lang.org/u/idanarye)\
**Post date:** [April 25, 2024, 2:21pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/8 "2024-04-25T14:21:14Z")

</div>

Just `loop match` please. If we allow any "expression w/ block" after `loop` then `loop loop loop { ... }` would be legal.

---

<div class="post-metadata">

**Author:** ![Noratrieb](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/noratrieb/32/12440_2.png) [@Noratrieb](https://internals.rust-lang.org/u/Noratrieb)\
**Post date:** [April 26, 2024, 8:27am UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/9 "2024-04-26T08:27:50Z")

</div>

What problem are you actually trying to solve? I don't see any problem here, the examples with the nested block are perfectly clear to read to me.

---

<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:** [April 26, 2024, 12:01pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/10 "2024-04-26T12:01:22Z")

</div>

```rust
let mut x = 10;
let mut y = 20;
loop if x != 0 {
    println!("x: {x}");
    x -= 1;
} else if y != 0 {
    println!("y: {y}");
    y -= 1;
}

```

such code is extremely dangerous, since you cannot figure that, the loop if is a infinite loop that forget a `break`, or a non-exaustive block that should adding an auto break. Your code could be

```rust
loop if x != 0 {
    println!("x: {x}");
    x -= 1;
} else {
    if y != 0 {
        println!("y: {y}");
        y -= 1;
    }
    break; // with accidently forget adding it.
}

```

I tried the current rust version, got

```rust
$ rustc --edition 2021 test2.rs && cat $_
warning: unreachable pattern
 --> test2.rs:6:9
  |
6 | _ => println!{"wtf?"}
  | ^
  |
  = note: `#[warn(unreachable_patterns)]` on by default

warning: 1 warning emitted

fn main(){
    let a:bool=true;
    match a {
        true => println!{"t"},
        false=> println!{"f"},
        _ => println!{"wtf?"}
    }
    if a {
        println!{"t again"}
    } else if !a {
        println!{"f again"}
    } else {
        println!{"wtf??"}
    }
}

```

It seems that, rust could detected unreachable match patterns, but cannot detect unreachable if-else patterns. Thus with your loop if statement, some overhead might be added accidently.

And for a most dangerous thing: How could you assume the missing branch is just a `break` rather than `doing nothing`? Suppose I have a data receiver `rec`, with a method `receive(&'a mut self, timeout_ms:u32)->Option<&'a mut [u8]>` Then I might write code like:

```rust
loop match rec.receive(1000) {
    Some(data)=>{if dealing_with(data).is_done() {break;}},
    None => () // waiting for more data
}

```

or just

```rust
loop if let Some(data) = rec.receive(1000) {
    if dealing_with(data).is_done() {
        break;
    }
}

```

In this case, how you could assume the else branch is `break` rather than `continue`?

---

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [April 26, 2024, 4:37pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/11 "2024-04-26T16:37:11Z")

</div>

I think I should've explained that part better in the post:

I find myself reaching for this kind of syntax a lot, particularly `loop match` (`break` as the default case of `match` inside a `loop`) and `loop if else` (`loop` with a manual break condition).

Having to stuff these in nested loops always felt a bit annoying in terms of refactoring and readability. The extra indentation felt especially unnecessary for `loop { match { .. } }`, and you have to shift around way more elements to convert `while { .. }` into `loop { if { .. } else { break }`. As a separate thing, this would also effectively coalesce all non-recursive looping into the `loop` keyword, which would seem more elegant and scannable than having a separate `while` keyword.

HOWEVER, I realized not too long after making the post that the implicit `break` is probably too confusing, especially in a systems language like Rust that tries to be very explicit and clear about the control flow for straightforward readability. Shame, but true....

Your friend, Yokin

---

<div class="post-metadata">

**Author:** ![Ddystopia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddystopia/32/10915_2.png) [@Ddystopia](https://internals.rust-lang.org/u/Ddystopia)\
**Post date:** [July 12, 2024, 9:40pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/12 "2024-07-12T21:40:34Z")

</div>

Sometimes you just cannot make a function, because it would be passing like 10 arguments, especially in embedded, where you are trying to pass _all_ resources manually, without using allocator to get some memory. It's really very common

---

<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:** [October 10, 2024, 9:41pm UTC](https://internals.rust-lang.org/t/allow-the-infinite-loop-keyword-to-prefix-expressions-w-blocks/20633/13 "2024-10-10T21:41:15Z")

</div>

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