# Ergonomic opposite of \`matches!\`

**URL:** <https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687>\
**Category:** language design\
**Created:** [December 28, 2020, 11:28pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687 "2020-12-28T23:28:59Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [December 28, 2020, 11:29pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/1 "2020-12-28T23:29:00Z")

</div>

This post is more a problem statement than a proposed solution, but I'm curious what people think.

[`std::matches`](https://doc.rust-lang.org/std/macro.matches.html) is a very useful macro. However, it can be a bit awkward when you want to branch on something _NOT_ matching:

```rust
if !matches!(val, pattern) {
    ...
}

```

One alternative is to use a `match` expression, but that's exactly what `matches!` is designed to simplify.

Another is to use a let binding:

```rust
let is_match = matches!(val, pattern);
if !is_match {
   ...
}

```

...but that's a lengthy workaround for the awkwardness of the `!matches!` syntax.

Below are some spitball proposals for solving this problem.

## Macro providing the opposite of `matches!`

Unfortunately there's not an immediately obvious name to me so it seems like mega bikeshed territory.

Some unenthusiastic proposals:

- `not_matches!`
- `mismatches!`

## Pie-in-the-sky new first-class branching keyword: `unless`

An `unless` keyword sure would be handy here, but I know a lot of people dislike the idea because it's easily abused to write unclear backwards-logic unless used in very specific circumstances where it's clearer, such as this one.

Still, I think it'd be my preferred solution to this problem, and would generally be nice whenever you want the opposite of a macro that returns a `bool`:

```rust
unless matches!(val, pattern) {
    ...
}

```

---

<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:** [December 28, 2020, 11:42pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/2 "2020-12-28T23:42:44Z")

</div>

Yet another alternative is to use `else`.

```rust
// rustfmt-style
if matches!(val, pattern) {
} else {
    ...
}

```

```rust
// single-line
if matches!(val, pattern) {} else {
    ...
}

```

_Edit:_ Or how about just adding some parentheses:

```rust
// yes, rustfmt actually doesn’t eat these
// and clippy doesn’t complain either
if !(matches!(val, pattern)) {
    ...
}

```

---

<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:** [December 29, 2020, 12:09am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/3 "2020-12-29T00:09:16Z")

</div>

Yet another alternative, as [pointed out in this prelude discussion](https://github.com/rust-lang/rust/issues/65512#issuecomment-748642322) (which also mentions a [previous internals thread](https://internals.rust-lang.org/t/the-is-not-empty-method-as-more-clearly-alternative-for-is-empty/10612/8)):

```rust
use std::ops::Not;
if matches!(val, pattern).not() {
   ...
}

```

> [@bascule](#):
>
> An `unless` keyword sure would be handy here, but I know a lot of people dislike the idea because it's easily abused to write unclear backwards-logic unless used in very specific circumstances where it's clearer, such as this one.

Perl and Ruby have this and I do agree it is handy in the right circumstances. But I also feel `unless` blocks become a liability due to confusion once combined with `else` blocks/chains. It could be restricted to the non-chained case, thought that would likely make it harder to justify a new keyword.

---

<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:** [December 29, 2020, 6:29am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/4 "2020-12-29T06:29:44Z")

</div>

I agree that `!matches!` looks silly, but it feels unlikely to me that something else would overcome the "additional thing to learn" hurdle. We don't even have `.is_not_empty()` on slices, for example.

> [@quinedot](#):
>
> But I also feel `unless` blocks become a liability due to confusion once combined with `else` blocks/chains. It could be restricted to the non-chained case, thought that would likely make it harder to justify a new keyword.

Agreed, but I think there's a way to keep that but give it value to the reader: force the body to be diverging. That way as soon as you see the `unless` keyword you know it's a precondition check, simple early return, etc. And in those the negation of the logic is actually helpful, since the condition is what's true _after_ the statement, just like with `assert!(x > 0);`.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [December 29, 2020, 12:30pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/5 "2020-12-29T12:30:06Z")

</div>

> [@quinedot](#):
>
> Yet another alternative, as [pointed out in this prelude discussion](https://github.com/rust-lang/rust/issues/65512#issuecomment-748642322)

Yes, please, `.not()` on `bool` suits the language patterns in a very ergonomic manner, **so feel free to add some support on that prelude suggestion** : while `matches!` is currently the main pervasive macro used in condition position, there may be more in the future, and we should have a generalized way to avoid writing `!something!(…)` code, or having to define the negation of each and every method / macro in existence (`not_something!`, _etc._)

While prefix `!` has the "advantage" of being less surprising for people used to other languages1, and while it can be made less unreadable by using a space after it: `if ! matches!(…)`, we will always have the problem of a condition using a method chain:

```rust
if !base.method1(…)
        .method2(…)
        .method3(…)
        .contains(…)
{
    …
}

```

_vs._

```rust
if base.method1(…)
       .method2(…)
       .method3(…)
       .contains(…)
       .not()
{
    …
}

```

1I am personally not a fan of that argument, since it leads to repeating errors from the past, but I recognize that showcasing too many syntax differences within a language must be avoided, at least when that language starts. But not only is Rust now a well-known language, it would also be unfair to qualify `.not()` as a bizarre syntax.

---

<div class="post-metadata">

**Author:** ![Lonami](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lonami/32/6774_2.png) [@Lonami](https://internals.rust-lang.org/u/Lonami)\
**Post date:** [December 29, 2020, 3:11pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/6 "2020-12-29T15:11:42Z")

</div>

[Recently](https://t.me/rustdevs/39332) I had to write the following:

```rust
assert!(!matches!(peer, tl::enums::Peer::Channel(_)));

```

It does get pretty funky really soon! But I think it isn't _too_ bad. Might be easy to miss accidentally during code review, but otherwise the syntax is using what everybody knows. The `not()` option was also suggested earlier, but I'm not a fan of it because the negation is _not_ where I expect it to be.

---

<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:** [December 29, 2020, 3:51pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/7 "2020-12-29T15:51:47Z")

</div>

> [@Lonami](#):
>
> The `not()` option was also suggested earlier, but I'm not a fan of it because the negation is _not_ where I expect it to be.

How about

```rust
assert!(bool::not(matches!(peer, tl::enums::Peer::Channel(_))));

```

then?

---

<div class="post-metadata">

**Author:** ![Lonami](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lonami/32/6774_2.png) [@Lonami](https://internals.rust-lang.org/u/Lonami)\
**Post date:** [December 29, 2020, 4:05pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/8 "2020-12-29T16:05:15Z")

</div>

That's a good alternative! A bit more verbose for sure, but definitely won't be overlooked on code review. However I'm going to stick with my funny looking approach for the time being ^^

---

<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:** [December 30, 2020, 5:40am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/9 "2020-12-30T05:40:18Z")

</div>

> [@Lonami](#):
>
> `assert!(!matches!(peer, tl::enums::Peer::Channel(_)));`

> **[matches::assert\_matches - Rust](https://docs.rs/matches/0.1.8/matches/macro.assert_matches.html)**
>
> API documentation for the Rust \`assert\_matches\` macro in crate \`matches\`.

---

<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:** [December 30, 2020, 5:50am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/10 "2020-12-30T05:50:07Z")

</div>

`assert_matches!(..)` isn't useful when you want `assert!( ! matches!( .. ) )`. The correct single macro would be `assert_not_matches!` or maybe `assert_not!(matches!(_))`.

That it's possible to make the mistake of assuming you could go from `assert!(!matches!(` to `assert_matches!(` just goes to show how easy it is to miss that leading `!` among the rest of the punctuation noise.

For the assert case specifically, I think it would make sense to have `assert_not!(`; it could provide a better error message than `assert!(!`.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [December 30, 2020, 9:02am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/11 "2020-12-30T09:02:37Z")

</div>

> [@CAD97](#):
>
> For the assert case specifically, I think it would make sense to have `assert_not!(` ; it could provide a better error message than `assert!(!` .

`assert!(!...)` seems like the easiest case for the new [“magic assert”](https://github.com/rust-lang/rust/issues/44838) to detect and give a better error message for.

---

<div class="post-metadata">

**Author:** ![Lonami](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lonami/32/6774_2.png) [@Lonami](https://internals.rust-lang.org/u/Lonami)\
**Post date:** [December 30, 2020, 9:24am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/12 "2020-12-30T09:24:38Z")

</div>

> [@scottmcm](#):
>
> [matches::assert\_matches - Rust](https://docs.rs/matches/0.1.8/matches/macro.assert_matches.html)

Ah, external dependencies, my nemesis 😃

I prefer to avoid them when possible, and if I can write `assert!(!` to avoid it I will. I'm sure the crate is very useful if you make extensive use of that or other of its macros though.

> [@Nemo157](#):
>
> `assert!(!...)` seems like the easiest case for the new [“magic assert”](https://github.com/rust-lang/rust/issues/44838) to detect and give a better error message for.

Wow the linked RFC is pretty cool and I had no idea it existed, I would love to see that. It seems there's no prior art section in the RFC, but for example, [pytest](https://docs.pytest.org/en/latest/) does this too:

```shell
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 1 item

test_sample.py F [100%]

================================= FAILURES =================================
_______________________________test_answer________________________________

    def test_answer():
> assert inc(3) == 5
E assert 4 == 5
E + where 4 = inc(3)

test_sample.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_sample.py::test_answer - assert 4 == 5
============================ 1 failed in 0.12s =============================

```

---

<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:** [December 30, 2020, 9:14pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/13 "2020-12-30T21:14:48Z")

</div>

> [@CAD97](#):
>
> That it's possible to make the mistake of assuming you could go from `assert!(!matches!(` to `assert_matches!(` just goes to show how easy it is to miss that leading `!` among the rest of the punctuation noise.

I think it's more that when I typed "assert\_mat" in my browser that's the link I got, and said "good enough".

---

<div class="post-metadata">

**Author:** ![Folyd](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/folyd/32/5801_2.png) [@Folyd](https://internals.rust-lang.org/u/Folyd)\
**Post date:** [December 31, 2020, 10:34am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/14 "2020-12-31T10:34:36Z")

</div>

I prefer `not_matches!`, `unmatch!`, or `matches!() == false`.

---

<div class="post-metadata">

**Author:** ![burjui](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/burjui/32/4113_2.png) [@burjui](https://internals.rust-lang.org/u/burjui)\
**Post date:** [January 1, 2021, 5:07pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/15 "2021-01-01T17:07:34Z")

</div>

This will never land in Rust, in any shape or form. That's because it's really a cruft for idealists, not a solution to a real problem, and I am talking about both `not_matches` and `unless`. Both are entirely superfluous and don't really improve source code readability, as with them you now have two ways of negation - `!` and `not_`/`unless`. Negation is too fundamental and simple a concept to have multiple ways of doing it. When considering a language change, make sure you test it in some way before suggesting it. For example, go on, write a `not_matches` macro, replace all of your `!matches` with `not_matches`, compare the sources and ask the following questions:

- Does it really improve readability that much?
- Was it that hard to write the macro by yourself?
- Can you improve the situation in some other way? Like using an IDE with proper highlighting of macro calls that is visually distinct from operators.

---

<div class="post-metadata">

**Author:** ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)\
**Post date:** [January 1, 2021, 5:35pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/16 "2021-01-01T17:35:36Z")

</div>

I think @burjui has it right in terms of what the pragmatic (non-) solution is to this. `!matches!(x, y)` is not great as an expression, but it's a general problem with all macros that expand to boolean expressions - including `cfg!()` etc, and most solutions don't seem to be proportional.

I still couldn't resist putting in my thoughts though, but it's not with the goal of changing Rust, just musing. The following could be an idea:

```rust
let x = Some(1);
if matches!(x, not Some(1)) {
} 

```

The negation is moved into the pattern. `matches!(x, not Some(1))` is equivalent to `!matches!(x, Some(1))`. This is readable but it has the drawback that a keyword like `not` has no precedent. And to be consistent, the same keyword should be usable in `if let` and `matches` as well - and have we ever seen utility for it there?

Matches example below. This doesn't feel easy to reason about at all, not a great feature 🙂

```rust
match (1, Some(2)) {
    not (1, _) => {}
    (1, None) => {}
    (1, Some(_)) => {}
    // The three cases should cover it
}

```

---

<div class="post-metadata">

**Author:** ![skysch](https://avatars.discourse-cdn.com/v4/letter/s/f05b48/32.png) [@skysch](https://internals.rust-lang.org/u/skysch)\
**Post date:** [January 1, 2021, 6:27pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/17 "2021-01-01T18:27:21Z")

</div>

I've hit a couple of situations where I thought it would be useful to be able to define patterns as items.

```rust
pattern<T> NOT_SOME: Option<T> = None;
pattern<T> SOME: Option<T> = Some(_);
pattern<T> SOME_1: Option<T> = Some(1);

```

If you could do that, you could write `matches!(x, NOT_SOME)` and have a reasonable way to share and document these things.

---

<div class="post-metadata">

**Author:** ![matt1985](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matt1985/32/4772_2.png) [@matt1985](https://internals.rust-lang.org/u/matt1985)\
**Post date:** [January 1, 2021, 9:55pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/18 "2021-01-01T21:55:23Z")

</div>

You can define "pattern aliases" using macros: [https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=24678e5e962a360b81cdbd394e6a84be](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=24678e5e962a360b81cdbd394e6a84be)

```rust
fn main(){
    macro_rules! not_some {
        ($($ty:ty)?) => { None $(::<$ty>)? }
    }

    if let not_some!() = None::<u32> {
        println!("Not Some");
    }
    
    if let not_some!(u32) = None {
        println!("Not Some");
    }

    macro_rules! tuple {
        ($($elem:pat),* $(,)?)=>{ ($($elem,)*) }
    }

    let tuple!(a, b) = (0, 1);
    println!("{} {}", a, b);
}

```

This obviously has all the downsides of macros, like having to write full paths inside the macro for `#[macro_export]`-ed macros, and macros being exported at the root of the crate.

---

<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:** [January 1, 2021, 10:36pm UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/19 "2021-01-01T22:36:54Z")

</div>

> [@matt1985](#):
>
> and macros being exported at the root of the crate.

Maybe not forever: [https://github.com/rust-lang/rust/pull/78166](https://github.com/rust-lang/rust/pull/78166)

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [January 2, 2021, 11:16am UTC](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687/20 "2021-01-02T11:16:10Z")

</div>

It didn't come to (my) mind before, but now that @bluss has mentioned them, negated patterns seem an "obviously" missing thing, the already mentioned caveats aside.

> [@matt1985](#):
>
> ```rust
> macro_rules! not_some {
> ($($ty:ty)?) => { None $(::<$ty>)? }
> }
> 
> ```

This is actually just a `None` pattern, not a `not Some(value)` pattern, which AFAICT cannot be easily expressed in a macro. E.g., a `not Some(5)` pattern would succeed on a `Some(3)` value as well.

Other than solving OP's problem statement, as already mentioned, they might be useful to filter out result patterns:

```rust
if matches!(val, not pattern) { ... } // addressing OP's problem
if let res @ not Err(Fatal) = fn_returning_result() { /* res is type Result */ }
if let Err(err @ not Fatal) = fn_returning_result() { /* err is error type */ }

```

Exact syntax of course TBD, as well as how this would interact with match `if` guards and `|` arms.

[Next page](https://internals.rust-lang.org/t/ergonomic-opposite-of-matches/13687.md?page=2)
