# "else match" Extending Conditional Syntax

**URL:** <https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780>\
**Category:** language design\
**Created:** [November 28, 2025, 3:59pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780 "2025-11-28T15:59:21Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Igor743646](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/igor743646/32/13839_2.png) [@Igor743646](https://internals.rust-lang.org/u/Igor743646)\
**Post date:** [November 28, 2025, 3:59pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/1 "2025-11-28T15:59:21Z")

</div>

## Motivation and Rationale

Rust's current conditional syntax provides excellent ergonomics with `if let` expressions, which have become a beloved feature for their clarity and conciseness. However, there exists an artificial limitation in the syntax that breaks the natural flow of conditional reasoning when developers need to combine boolean conditions with structural pattern matching.

The proposed extension addresses a fundamental inconsistency: while `if let` enjoys first-class support in both primary and secondary conditional positions, the more powerful `match` expression is artificially constrained to require block nesting when following an `else` clause.

## User Experience and Readability Benefits

The proposed syntax directly maps to natural thought patterns. When reading code, developers think "if this condition, then this behavior, otherwise try this pattern matching." The current syntax forces unnecessary block nesting that breaks this mental flow.

**Current syntax:**

```rust
if condition {
    handle_positive();
} else {
    match value {
        Pattern1 => handle_pattern1(),
        Pattern2 => handle_pattern2(),
    }
}

```

**Proposed syntax:**

```rust
if condition {
    handle_positive();
} else match value {
    Pattern1 => handle_pattern1(),
    Pattern2 => handle_pattern2(),
}

```

## Consistency and Design Philosophy

The proposal maintains consistency with existing conditional syntax patterns while extending them logically. Rust already demonstrates that conditional syntax should serve the developer's logical flow rather than impose arbitrary structural constraints.

The precedent of `if let` in secondary positions establishes that pattern matching belongs in conditional contexts, and `match` as the more general form deserves equal syntactic treatment.

```rust
fn parse_config(input: &str) -> Result<Config, ParseError> {
    if input.trim().is_empty() {
        Err(ParseError::EmptyInput)
    } else match input.parse::<toml::Value>() {
        Ok(toml_value) => {
            match toml_value.as_table() {
                Some(table) => Config::from_table(table),
                None => Err(ParseError::InvalidFormat),
            }
        }
        Err(_) => match input.parse::<json::Value>() {
            Ok(json_value) => Config::from_json(&json_value),
            Err(_) => Err(ParseError::UnsupportedFormat),
        }
    }
}

```

or

```rust
if let Some(resource) = acquire_resource() && resource.is_valid() {
    use_resource(resource); // resource is moved and available here
} else match get_alternative_data() { // different data source
    Alternative::Good(data) => process(data),
    Alternative::Bad => fallback(),
}

```

## Addressing the `match` guard alternatives

While pattern guards can technically achieve similar results, they introduce significant practical drawbacks that make the proposed syntax extension valuable:

```rust
// Using pattern guards - problematic for complex conditions
match value.hard_job() { // This executes even if first condition passes!
    _ if expensive_validation() && another_check() && yet_another_condition() => handle_positive(),
    Pattern1 => handle_pattern1(),
    Pattern2 => handle_pattern2(),
}

// Proposed syntax - clear separation of concerns
if expensive_validation() && another_check() && yet_another_condition() {
    handle_positive();
} else match value { // Only evaluated when needed
    Pattern1 => handle_pattern1(),
    Pattern2 => handle_pattern2(),
}

```

Pattern guards evaluate all patterns sequentially, potentially executing expensive computations unnecessarily. The conditional approach allows early termination and avoids pattern evaluation when the boolean condition already determines the flow.

## Cognitive Load

```rust
// Guards obscure the primary logic flow
match input {
    _ if input.starts_with("HTTP/1.1") && input.contains("200 OK") && !input.contains("Connection: close") => handle_keepalive(),
    _ if input.starts_with("HTTP/1.1") && input.contains("200 OK") => handle_response(),
    _ if input.starts_with("HTTP/1.1") => handle_http_error(),
    _ if input.starts_with("HTTP/2") => handle_http2(),
    // ... more complex guard chains
}

// Proposed syntax - clear conditional flow
if input.starts_with("HTTP/1.1") && input.contains("200 OK") && !input.contains("Connection: close") {
    handle_keepalive();
} else if input.starts_with("HTTP/1.1") && input.contains("200 OK") {
    handle_response();
} else match input {
    line if line.starts_with("HTTP/1.1") => handle_http_error(),
    line if line.starts_with("HTTP/2") => handle_http2(),
    _ => handle_unknown(),
}

```

## Practical Impact

The proposed syntax enables clear separation between boolean logic (which may involve side effects, moves, or expensive computations) and structural pattern matching, which guards cannot provide effectively.

This addresses real-world pain points in codebases of moderate complexity. Applications dealing with user input validation, configuration processing, and data transformation frequently encounter scenarios where boolean preconditions naturally precede structural pattern matching.

This proposal aims to enhance Rust's conditional syntax consistency and developer experience. What do you think about this proposal?

---

<div class="post-metadata">

**Author:** ![epidemian](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epidemian/32/11396_2.png) [@epidemian](https://internals.rust-lang.org/u/epidemian)\
**Post date:** [November 28, 2025, 5:54pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/2 "2025-11-28T17:54:13Z")

</div>

Isn’t the initial snippet equivalent to?

```rust
match value {
    _ if condition => handle_positive(),
    Pattern1 => handle_pattern1(),
    Pattern2 => handle_pattern2(),
}

```

The array/slice matching example can also be written as a single `match` AFAICT.

---

<div class="post-metadata">

**Author:** ![Kivooeo](https://avatars.discourse-cdn.com/v4/letter/k/aeb1de/32.png) [@Kivooeo](https://internals.rust-lang.org/u/Kivooeo)\
**Post date:** [November 28, 2025, 6:06pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/3 "2025-11-28T18:06:56Z")

</div>

> [@epidemian](#):
>
> The array/slice matching example can also be written as a single `match` AFAICT.

Yes:

```rust
    match array {
        a if a.is_empty() => handle_empty(),
        [x] => handle_single(*x),
        [a, b] => handle_pair(*a, *b),
        a => handle_complex_case(a),
    }

```

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [November 28, 2025, 6:21pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/4 "2025-11-28T18:21:16Z")

</div>

I'm cautiously positive about this suggestion, but the second example can already be written as a single `match`...

```rust
match array {
    [] => handle_empty(),
    [x] => handle_single(*x),
    [a, b] => handle_pair(*a, *b),
    more => handle_more(more),
}

```

([see here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=880648039603fc67e00cdea8149aa3d8))

Additionally, I feel like this proposal is going to make people want these additional features:

- match statements in other positions within an if-else chain:
  - `match foo { ... } else ...`, where the `else` clause is entered if none of the match cases matched
  - `if ... { ... } else match { ... } else ...`, similarly

- the compiler does flow analysis over an entire if-else chain and doesn't require embedded `match` statements to include cases that cannot reach them (to some extent this is already a pain point for `match` inside `else [if]` blocks, but if `match` is a first-class citizen of if-else chains, that makes it more surprising when this doesn't work)

You should think about whether you want to roll these features into your proposal.

---

<div class="post-metadata">

**Author:** ![Igor743646](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/igor743646/32/13839_2.png) [@Igor743646](https://internals.rust-lang.org/u/Igor743646)\
**Post date:** [November 28, 2025, 6:31pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/5 "2025-11-28T18:31:23Z")

</div>

Thank you very much for the review. I have expanded the proposal based on your comment. At the moment, I am proposing to reduce the cognitive load on conditions within match options, as this becomes cumbersome and "late-computed" for more complex conditions

---

<div class="post-metadata">

**Author:** ![Igor743646](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/igor743646/32/13839_2.png) [@Igor743646](https://internals.rust-lang.org/u/Igor743646)\
**Post date:** [November 28, 2025, 7:02pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/6 "2025-11-28T19:02:00Z")

</div>

These are excellent points about the consistency implications of the proposal. I agree that treating match as a first-class conditional citizen creates expectations of symmetrical functionality.

### Regarding match with else clauses

```rust
// This would indeed be expected if we extend match to else position
match foo {
    Pattern1 => handle1(),
    Pattern2 => handle2(),
} else {
    // Handle when no patterns match
    fallback()
}

```

However, this conflicts with Rust's exhaustiveness checking philosophy. The match expression is designed to be exhaustive - if properly structured, no patterns should remain unmatched. I think, introducing an else clause would undermine this safety guarantee and create confusion about when exhaustiveness applies.

### About flow analysis complexity:

I am skeptical about the complexity of analyzing the execution flow.

```rust
fn foo0(opt: Option<i32>) -> i32 {
    if let Some(x) = opt
        && x > 0
    {
        x
    } else match opt { // Proposal syntax
        Some(y) if y <= 0 => std::process::exit(y),
        None => std::process::exit(1),
    }
}

fn foo1(opt: Option<i32>) -> i32 {
    if let Some(x) = opt
        && x > 0
    {
        x
    } else {
        match opt {
            Some(y) if y <= 0 => std::process::exit(y),
            None => std::process::exit(1),
            // _ => todo!() - Error: missing match arm: `Some(_)` not covered
        }
    }
}

fn foo2(opt: Option<i32>) -> i32 {
    if let Some(x) = opt
        && x > 0
    {
        x
    } else if let Some(y) = opt
        && y <= 0
    {
        std::process::exit(y)
    } else if let None = opt {
        std::process::exit(1)
    }
    // Error: `if` may be missing an `else` clause
    // `if` expressions without `else` evaluate to `()`
}

```

I believe the original proposal should remain focused on the `else match` extension specifically, as it addresses the clear inconsistency between `if let` and `match` syntax without introducing exhaustiveness complications. The additional features you mention would require separate, more complex proposals that address the fundamental design questions around non-exhaustive matches and enhanced flow analysis.

The core benefit of `else match` - eliminating block nesting while maintaining existing safety guarantees - justifies its inclusion without expanding into these more complex territory. However, it makes sense to consider the potential compatibility of this syntax if the addition of `match else` is considered in the future. As of now, I believe that `else match` will be:

1. a syntactic sugar for nested match in else
2. match options will technically be expanded in the `if let` construct

---

<div class="post-metadata">

**Author:** ![pitaj](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pitaj/32/11262_2.png) [@pitaj](https://internals.rust-lang.org/u/pitaj)\
**Post date:** [November 28, 2025, 7:33pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/7 "2025-11-28T19:33:29Z")

</div>

So far I still haven't seen an example that couldn't just be written as a single match. I think you need some better examples, ideally from real-world code.

---

<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:** [November 28, 2025, 8:19pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/8 "2025-11-28T20:19:43Z")

</div>

This is a _very_ old idea. The first version of it I found is from 2016 [If-else could allow omitting braces on the else · Issue #1616 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/issues/1616) and then someone wrote an RFC that was rejected in 2017 [Add 'else match' blocks to if expressions. by phoenixenero · Pull Request #1712 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/1712#issuecomment-277508882)

Has anything materially changed since then? Nothing comes to mind to me.

> [@Igor743646](#):
>
> The proposed extension addresses a fundamental inconsistency: while `if let` enjoys first-class support in both primary and secondary conditional positions, the more powerful `match` expression is artificially constrained to require block nesting when following an `else` clause.

Reusing an 8-year old post to address this: [https://github.com/rust-lang/rfcs/pull/1712#issuecomment-277857697](https://github.com/rust-lang/rfcs/pull/1712#issuecomment-277857697).

> [@Igor743646](#):
>
> **Proposed syntax:**
> 
> ```rust
> if condition {
> handle_positive();
> } else match value {
> Pattern1 => handle_pattern1(),
> Pattern2 => handle_pattern2(),
> }
> 
> ```

If it's something that can't just be written as

```rust
match value {
    _ if condition => handle_positive(),
    Pattern1 => handle_pattern1(),
    Pattern2 => handle_pattern2(),
}

```

then the extra nesting is maybe even good.

> [@Igor743646](#):
>
> The core benefit of `else match` - eliminating block nesting while maintaining existing safety guarantees - justifies its inclusion without expanding into these more complex territory.

_If_ this was sufficient justification to add it, it's also be sufficient justification to add `else for` and `else loop` and a whole bunch of other stuff -- even things like `loop for`. So I think you need a much stronger reason that `else match` is special, or you do need to argue that those other extensions would also be similarly good and probably worth doing to.

> [@Igor743646](#):
>
> match options will technically be expanded in the `if let` construct

I don't think that the _syntactic_ version of this is what people would want in `if let`.

More likely, to me, if there was going to be an `else match` it'd be a typestate-style thing so that you can do

```rust
let Ordering::Equal = … stuff …
else match {
    Ordering::Less => …,
    Ordering::Greater => …,
};

```

where it's not a _syntactic_ contraction, but an extended whole-construct thing where the exhaustiveness checking is aware of _both_ the `let` pattern _and_ the `match` patterns, so you can handle the remainder of the value that was pattern-matched in a nice way that's not _possible_ with today's `let`-`else`.

Just removing an extra set of braces in there doesn't seem worth bothering at all, but giving new expressivity might be.

(That said, it's still just convenience, as it's already _possible_ with plain match, so it'd need a survey _showing_ in real code that it'd be widely applicable, not just "well it sounds nice" or "it happens sometimes".)

---

<div class="post-metadata">

**Author:** ![Igor743646](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/igor743646/32/13839_2.png) [@Igor743646](https://internals.rust-lang.org/u/Igor743646)\
**Post date:** [November 28, 2025, 9:03pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/9 "2025-11-28T21:03:19Z")

</div>

What about an example from real code:

1. [svg\_loader.rs - source](https://docs.rs/egui_extras/0.33.2/src/egui_extras/loaders/svg_loader.rs.html#74)
2. [parker.rs - source](https://docs.rs/crossbeam-utils/0.8.21/src/crossbeam_utils/sync/parker.rs.html#368)
3. [binding\_model.rs - source](https://docs.rs/wgpu-core/27.0.3/src/wgpu_core/binding_model.rs.html#459)

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [November 28, 2025, 9:30pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/10 "2025-11-28T21:30:11Z")

</div>

> [@scottmcm](#):
>
> I think you need a much stronger reason that `else match` is special

`match` and `if`..`else` both select one of several "body" expressions to evaluate based on a series of "conditions" and/or "patterns". So they are related to each other, and they are both _different_ from looping constructs. So I don't think your slippery slope argument goes through.

However,

> [@scottmcm](#):
>
> an extended whole-construct thing where the exhaustiveness checking is aware of _both_ the `let` pattern _and_ the `match` patterns, so you can handle the remainder of the value that was pattern-matched in a nice way that's not _possible_ with today's `let`-`else` ... might be [worth bothering with]

fully agreed with this. I see value in the proposal _if and only if_ exhaustiveness checks consider the entire if-else-match chain.

---

<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:** [November 28, 2025, 10:00pm UTC](https://internals.rust-lang.org/t/else-match-extending-conditional-syntax/23780/11 "2025-11-28T22:00:29Z")

</div>

> [@zackw](#):
>
> I see value in the proposal _if and only if_ exhaustiveness checks consider the entire if-else-match chain.

Note that this advantage _only_ applies to `let`-`else match`.

It doesn't apply to `if BOOL_COND { … } else match … { … }`, since that's not a pattern.

It also doesn't apply to `if let PAT = EXPR { …A… } else match BLAH { … }` because they're matching different things.

And the special case of `if let PAT = EXPR { …A… } else match { PAT2 => EXPR3, … }` doesn't make sense to offer because that's just `match EXPR { PAT => …A…, PAT2 => EXPR3, … }`.

So even assuming that such a proposal would be good for `let`-`else match`, it still doesn't mean that `if`-`else match` is good.

* * *

Really, part of the problem is that if-else chaining is just not a great way to do things. The much better construct is [`cond`](https://docs.scheme.org/schintro/schintro_21.html#SEC21), which would side-step all these problems by not needing chaining. (In the same way that there's no chaining for multiple `match` arms, since the construct encloses all of them.)

I like what [boats had to say](https://github.com/rust-lang/rfcs/pull/1712#issuecomment-279959073) about this:

> `else if` is an expected/understood construct from other languages. Like much of our control flow\*, `if`/`else` is empowered by familiarity as much as convenience, and making it act strangely from other languages only because its more general in some abstract sense doesn't make it more intuitive or usable.
> 
> \*The most glaring example of this "familiarity sugar" is `while`: I doubt we would have considered that use case deserving of sugar if it weren't for the fact that its a universally common construct in imperative languages.

Notably, even in languages where `if (cond) { BLOCKA } else switch (EXPR) { ARMS }` is legal, it seems to be against the de-facto rules to ever write it that way, with every style guide saying that `else` needs to have braces even though the language doesn't.
