# \[Pitch\] is case expressions

**URL:** <https://forums.swift.org/t/pitch-is-case-expressions/64185>\
**Category:** Pitches\
**Created:** [April 4, 2023, 4:03pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185 "2023-04-04T16:03:02Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [April 5, 2023, 1:31am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/21 "2023-04-05T01:31:30Z")

</div>

Again, I'll note that dot-syntax is merely a theoretical suggestion that I find easiest to motivate given the existence of optional-chaining, and that we need ways to compose property access with case access, and we need ways to compose key paths with case paths.

I'd be perfectly happy with _any_ syntax here, but I still haven't seen any suggested alternatives fleshed out that allow for these compositions.

I'll try not to derail the topic with dot-syntax further, but will say that the lack of clarity around expressive enum payload access makes it much harder to evaluate this pitch, and whatever syntax we _do_ come up with might motivate a _different_ syntax than `is case`.

---

<div class="post-metadata">

**Author:** ![matthewcheok](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/matthewcheok/32/29773_2.png) [@matthewcheok](https://forums.swift.org/u/matthewcheok)\
**Post date:** [April 5, 2023, 2:31am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/22 "2023-04-05T02:31:56Z")

</div>

Stephen, thanks for your feedback. While I'm just as excited for first class support for case paths, I see them as a more general tool that's more capable, and fits in right alongside `is case`.

One of the main use cases of `is case` is to directly test against enum cases and where you might be able to achieve that with case paths or dot-syntax access, it's definitely not as concise or ergonomic.

## Comparing `is case` to case paths

Let's jump directly to what could be said to be the most ideal syntax for case paths (ignoring the setting/embedding functionality for the sake of this example):

```swift
enum Destination { 
  case .messageThread(id: Int)
}

// Constructing a case path, treated similarly to key paths and may compose with them
let threadPath = \Destination.messageThread 

// Extracting values
let destination = Destination.messageThread(id: 42)
let id = destination[keyPath: \.messageThread] // Int?

// Checking against an enum case
destination[keyPath: \.messageThread] != nil // true
// Usage inline 
HeaderView(inThread: destination[keyPath: \.messageThread] != nil)

// Contrasted with the proposed `is case` syntax
destination is case .messageThread // true
// Usage inline
HeaderView(inThread: destination is case .messageThread)

```

To answer your question: if we _are_ given such a syntax in the future, would we still want the additional surface area of `is case` ? I do think `is case` is able to express the intent to check if an enum is a particular case much more succinctly and with less ceremony than the case path alternative.

This is especially so if the case is known at compile-time. The case path approach is more useful if we needed to refer to a case in the abstract without instantiating the enum.

In particular, the ability to match a pattern directly inline (when extended with the `~=` operator) could be very useful as in the following Point-free example

> **Show more**
>
> Assuming context from the code sample in this [case study](https://github.com/pointfreeco/swift-composable-architecture/blob/52c4a01437aa1429dab4e6b460062a8b7d6aeab6/Examples/CaseStudies/SwiftUICaseStudies/01-GettingStarted-Bindings-Forms.swift#L35):
> 
> ```swift
> enum Action {
> case binding(BindingAction<State>)
> }
> 
> // With `is case`, tacking on functionality when `Action` matches a specific binding
> if action is case .binding(\.$stepCount) {
> ...
> }
> 
> // The same with a case path (we can't leverage the `~=` operator here)
> if action[keyPath: \.binding]?.keyPath == \.$stepCount {
> ...
> }
> 
> ```

## Comparing `is case` to dot-syntax access for associated values on enums

Suppose the compiler makes accessing associated values as easily as properties (without code synthesis), vended as optionals:

```swift
enum Destination {
  case inbox
  case messageThread(Int)
}

// Assume the following is available implicitly:
extension Destination {
  var messageThread: Int? // Returns the associated value or `nil` if the value is not in the `messageThread` case
}

// Checking against an enum case
destination.messageThread != nil // true
// Usage inline 
HeaderView(inThread: destination.messageThread != nil)

// Contrasted with the proposed `is case` syntax
destination is case .messageThread // true
// Usage inline
HeaderView(inThread: destination is case .messageThread)

```

Here I would still say that `is case` describes the intent more succinctly without the ceremony of comparing to `nil`.

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [April 5, 2023, 2:58am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/23 "2023-04-05T02:58:32Z")

</div>

After looking over the pitch a second time, and understanding that it aims solely to improve the ergonomics of pattern matching, I believe the proper spelling for this feature is “`matches`”.

As in, “`<expression> matches <pattern>`”.

In support of this, note that we are talking about pattern matching. And in every discussion or description of pattern matching, it is called “pattern matching”, because the name of the operation is pattern matching, and the thing that it does is match patterns.

Swift takes pride in naming things well, and this is a great opportunity to supersede the notoriously unintuitive “`if case`” spelling with something far more natural, that reads correctly as written, and which actually describes the operation being performed.

Using “`matches`” will make pattern-matching code much easier to read and understand.

* * *

Here are some examples from the pitch, with `matches` as the keyword:

```swift
print(destination matches .inbox) // false
print(destination matches .messageThread) // true
print(destination matches .messageThread(id: 0)) // false
print(destination matches .messageThread(id: 42)) // true

foo matches .bar // enum case
foo matches .bar(42) // enum case with associated values
foo matches .bar(42, _) // enum case with partially matched associated values
foo matches 42 // integer literal
foo matches true // boolean literal
foo matches "A string" // string literal
foo matches bar // other expression

```

To me, they are a lot more sensible this way.

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 5, 2023, 3:04am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/24 "2023-04-05T03:04:25Z")

</div>

> [@stephencelis](#):
>
> If we had this more general extraction functionality, we get the "case checking" mechanism this pitch proposes for free:
> 
> ```swift
> // Instead of `destination is case .messageThread`:
> destination.messageThread != nil // true
> 
> ```

I find this sort of syntax appealing at a surface level, but there are a few reasons I think synthesized "is case" or "as case" declarations aren't a good fit here.

For one, I'm not so sure we would be happy with enabling this sort of functionality for all enums by default. For enum cases without associated values we'd have to synthesize `Void?` accessors, which I find especially unidiomatic:

```swift
enum Destination {
  case inbox
  case settings
  case profile
}

destination.inbox // Void?
destination.settings // Void?
destination.profile // Void?

```

Littering all of these unidiomatic properties on enums that don't get any value out of them seems less-than-ideal. This isn't an issue with a new operator like `is case` since operators don't show up in autocomplete.

Another important aspect is that there isn’t an existing precedent for synthesizing these sorts of user-facing properties by default. In cases where the compiler synthesizes declarations, they're either opt-in using advanced language features (`@dynamicMemberLookup`) or the synthesized declarations aren’t so directly user-facing (e.g. Codable synthesis, which isn't ever really called directly by the user).

The developer experience of working with these synthesized properties would likely be a bit poor. One practical limitation is that it wouldn’t possible to add documentation for these properties. When using the strongly-typed KeyPath API, `@dynamicMemberLookup`'s synthesized properties inherit the documentation of the property they reference via the keypath. This doesn't work well for enum cases, since any documentation associated with the case wouldn't do a good job describing a declaration with a different type.

Most users of Swift can accomplish quite a lot without ever directly consuming any of these sorts of synthesized declarations. To me this indicates that user-facing declaration synthesis isn't really appropriate for functionality as core to the language as working with enum values.

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 5, 2023, 3:15am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/25 "2023-04-05T03:15:29Z")

</div>

> [@Nevin](#):
>
> After looking over the pitch a second time, and understanding that it aims solely to improve the ergonomics of pattern matching, I believe the proper spelling for this feature is “`matches`”.
> 
> As in, “`<expression> matches <pattern>`”.

I find this appealing since it's just a single keyword rather than two. I'd certainly support this sort of spelling as an alternative to `is case`.

I think it's worth considering that the language consistently uses `case x` everywhere you can do pattern matching (right?). To me this feels valuable because it clearly establishes a relationship between `if case`, `switch { case: }` and `is case`, and suggests that they support the same type of pattern matching functionality.

On the other hand, perhaps establishing a bit of contrast between the two use cases is actually a good idea. Would using a different keyword here make it less surprising that you aren't able to bind associated values when using this new expression type? (e.g. that you can only bind associated values with `case .messageThread(let id)` and not `matches .messageThread`)

---

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [April 5, 2023, 3:49am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/26 "2023-04-05T03:49:17Z")

</div>

@matthewcheok @cal Thanks for both replying. I'm going to de-emphasize my dot syntax solution again, since the conversation seems to be getting hung up on details around that, but my main point is that the syntax of `is case` (or `matches`) might be designed differently if we could first shed some light on the following problem spaces:

- What should it look like to extract an enum payload in an expression?
- What should it look like to compose property access with case access?
- What should it look like to compose key paths with case paths?

It's quite possible that `is case` still fits in perfectly well with whatever solutions to the above problems ends up looking like. It's also quite possible that `is case` can help shed some light on how these solutions should be designed.

On the other hand, it's might be that solutions to the above problems leads to an alternative design that ties everything together differently.

Does anyone have a vision for what solutions to these problems may look like, especially from the perspective of `is case`?

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 5, 2023, 3:49am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/27 "2023-04-05T03:49:23Z")

</div>

> [@AlexisQapa](#):
>
> How would this work when two cases have the same name ?

`is case <pattern>` would have the same behavior as a `switch` with `case <pattern>`.

That being said, I'm not exactly sure what the expected behavior of a switch statement would be in cases where an enum has multiple cases with the same base name. I'm a bit confused when I run this sample code:

```swift
enum MyEnum {
  case foo(bar: Int)
  case foo(baaz: Int)
}

func match(_ value: MyEnum) {
  switch value {
    case .foo:
      print("matches .foo")
    default:
      print("doesn't match .foo")
    }
}

match(.foo(bar: 42)) // prints "doesn't match .foo"
match(.foo(baaz: 42)) // prints "matches .foo"

```

I don't know how the compiler chooses which case to match here. It seems arbitrary.

Even more strangely, this code compiles successfully but crashes with _"Fatal error: unexpected enum case while switching on value of type 'MyEnum'"_:

```swift
enum MyEnum {
  case foo(bar: Int)
  case foo(baaz: Int)
}

func match(_ value: MyEnum) {
  switch value {
    case .foo:
      print("matches .foo")
    }
}

match(.foo(baaz: 42)) // prints "matches .foo"
match(.foo(bar: 42)) // causes a crash

```

So this seems pretty poorly defined today, and I have no clue what the expected behavior would be.

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 5, 2023, 4:15am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/28 "2023-04-05T04:15:15Z")

</div>

> [@stephencelis](#):
>
> - What should it look like to extract an enum payload in an expression?
> - What should it look like to compose property access with case access?
> - What should it look like to compose key paths with case paths?

I find the examples you shared above to be pretty reasonable, although I understand your hesitation around the extra parenthesis that would be required:

> [@stephencelis](#):
>
> ```swift
> let id/*: Int?*/ = destination as case .messageThread
> 
> (screen as case .messageThread).map(MessagesView.init(inThread:))
> 
> // case foo(bar: Int, baz: Int)
> _: Int? = (value as case .foo)?.bar
> _: Bool? = (value as case .foo)?.baz.isMultiple(of: 2)
> 
> \Destination.(as case .messageThread)
> 
> ```

I wonder if a spelling like `.isCase(<pattern>)` and `.asCase(<enum-case>`) would feel better here:

```swift
// isCase(<pattern>)
let destination = Destination.messageThread(id: 42)
print(destination.isCase(.inbox)) // false
print(destination.isCase(.messageThread)) // true
print(destination.isCase(.messageThread(id: 0))) // false
print(destination.isCase( .messageThread(id: 42))) // true

// asCase(<enum-case>)
let id/*: Int?*/ = destination.asCase(.messageThread)

screen.asCase(.messageThread)?.map(MessagesView.init(inThread:))

// case foo(bar: Int, baz: Int)
_: Int? = value.asCase(.foo)?.bar
_: Bool? = value.asCase(.foo)?.baz.isMultiple(of: 2)

\Destination.asCase(.messageThread)

```

This seems like it may be the best of both worlds -- it's a simple syntax that doesn't require quite so many magic synthesized properties, but also doesn't use an operator so works really naturally within expressions, optional chaining, and key paths.

Thoughts?

I could see how introducing an `is case` expression could potentially cut us off from this sort of direction, since it would be weird to have `expr is case x` and `expr.asCase(x)`. Perhaps `expr matches x` and `expr.asCase(x)` could coexist nicely though.

---

<div class="post-metadata">

**Author:** ![austintatious](https://avatars.discourse-cdn.com/v4/letter/a/ce73a5/32.png) [@austintatious](https://forums.swift.org/u/austintatious)\
**Post date:** [April 5, 2023, 4:52am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/29 "2023-04-05T04:52:53Z")

</div>

Absolutely agree.

---

<div class="post-metadata">

**Author:** ![ibex](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ibex/32/30439_2.png) [@ibex](https://forums.swift.org/u/ibex)\
**Post date:** [April 5, 2023, 5:07am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/30 "2023-04-05T05:07:15Z")

</div>

> [@cal](#):
>
> expr.asCase(x)

```swift
expr.asCase(x) // yucky 
expr matches x // elegant but requires new keyword
expr =~ x // even better

```

---

<div class="post-metadata">

**Author:** ![hisekaldma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hisekaldma/32/1146_2.png) [@hisekaldma](https://forums.swift.org/u/hisekaldma)\
**Post date:** [April 5, 2023, 6:31am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/31 "2023-04-05T06:31:45Z")

</div>

I just wanted to say that I think the proposed `is case` syntax is great _exactly as proposed_.

- This would not be better spelled with another keyword. For better or worse, `case` is the keyword already used for pattern matching in the language. Using `case` here makes it immediately clear to me how this works: patterns here work the same as in other pattern matches, except you can’t bind to new variables since there’s no new scope.
- This would not be better spelled with `==`. The `==` operator tests for equality. That is not what’s happening here. What’s happening here is pattern matching.
- This would not be better as some imagined case projection mechanism. I too want case paths and better ways of reading and writing case payloads, but all those features are orthogonal to this. The most common use of this would be matching against cases _when you don’t care about the payload_. I would also imagine `shape is case .path` to have better performance than anything that ends with `!= nil`, since it doesn’t need to extract the payload. (As always, maybe the compiler would optimize it away, but if the payload is large and this is in a hot `filter`, do you really want to rely on that maybe?)

---

<div class="post-metadata">

**Author:** ![georgebarnett](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/georgebarnett/32/9137_2.png) [@georgebarnett](https://forums.swift.org/u/georgebarnett)\
**Post date:** [April 5, 2023, 9:24am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/32 "2023-04-05T09:24:06Z")

</div>

This would be a useful addition – thank you for pitching it!

I often run into this problem in tests and resort to writing helpers for each case to extract associated values or check if the value is that case. This is tedious, error prone and results in numerous lines of boilerplate.

I like the proposed spelling of this: `is case` is clear at the point of use, consistent with pattern matching and indicates a boolean result.

> [@matthewcheok](#):
>
> Open question: should `x ?? y is case .z` be treated as `x ?? (y is case .z)` or `(x ?? y) is case .z`? The former matches `is`'s CastingPrecedence, designed around `as?`, but the latter is still an option, and both have plausible uses: `alwaysDark ?? (systemMode is case .dark)` vs `(overriddenMode ?? systemMode) is case .dark`. The precedence of `is case` should be higher than `ComparisonPrecedence` no matter what, though.

My gut feeling is that `x ?? y is case .z` should be treated as `x ?? (y is case .z)`; only in that I think it would be a little surprising if it was treated differently to `x ?? y is Foo`.

---

<div class="post-metadata">

**Author:** ![kiel](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kiel/32/1392_2.png) [@kiel](https://forums.swift.org/u/kiel)\
**Post date:** [April 5, 2023, 10:29am UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/33 "2023-04-05T10:29:58Z")

</div>

I see there is a [case detection macro here](https://github.com/DougGregor/swift-macro-examples/blob/main/MacroExamplesPlugin/CaseDetectionMacro.swift) — example [here](https://github.com/DougGregor/swift-macro-examples/blob/main/MacroExamples/main.swift). Could this macro be enhanced to achieve the same functionality as this pitch?

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 5, 2023, 1:46pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/34 "2023-04-05T13:46:01Z")

</div>

That macro generates `is<case>` declarations for each enum case, like this:

```swift
@CaseDetection // opt-in macro
enum Destination {
  case inbox
  case messageThread(id: Int)
}

// Generated code:
extension Destination {
  var isInbox: Bool { ... }
  var isMessageThread: Bool { ... }
}

```

I'm really excited about macros, but there are a few reasons why I think this sort of macro isn't the right solution here:

Even if the macro was defined in the standard library, actually adopting the macro on your enum is op-in, so this would only be usable in cases where the author of the enum declaration opted-in to this functionality.

Other code synthesis functionality like this is typically opt-in (e.g. `CaseIterable`) but that's because the code synthesis adds a new semantic guarantees that the author needs to consider going forwards. This isn't the case with something like `@CaseDetection`, since it doesn't impose any additional semantic requirements.

Any solution here would ideally be supported by default for all enum declarations, so users have a consistent way of working with all enum values across their entire project. But even if we could force this macro to be applied to all enum declarations, I don't think we would want to -- the generated properties would result in a large code size increase.

This is why an operator at the call site, like `<expr> is case <pattern>`, makes the most sense to me.

That being said, I could imagine using a macro defined in the standard library that we use in place of an `is case` operator. For example:

```swift
let destination = Destination.messageThread(id: 42)
print(@isCase(destination, .inbox)) // false
print(@isCase(destination, .messageThread)) // true

// Generates:

let destination = Destination.messageThread(id: 42)
print({ if case .inbox = destination { true } else { false }}()) // false
print({ if case .messageThread = destination { true } else { false }}()) // true

```

That's definitely a neat option with a majority of the benefits of defining a new operator. I find this significantly less idiomatic than an operator, though, particularly since it's a free function.

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [April 5, 2023, 3:15pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/35 "2023-04-05T15:15:58Z")

</div>

> [@cal](#):
>
> I think it's worth considering that the language consistently uses `case x` everywhere you can do pattern matching (right?). To me this feels valuable because it clearly establishes a relationship between `if case`, `switch { case: }` and `is case`, and suggests that they support the same type of pattern matching functionality.

> [@hisekaldma](#):
>
> For better or worse, `case` is the keyword already used for pattern matching in the language. Using `case` here makes it immediately clear to me how this works: patterns here work the same as in other pattern matches, except you can’t bind to new variables since there’s no new scope.

I want to address these points, because I think it is really important. They are both appeals to consistency: “We already use this spelling for a similar thing, so we should use it for this new thing.” There have been a few other comments along the same lines, not to mention the pitch itself. And I want to push back quite strongly:

&nbsp; **Consistent use of a bad design, is bad.**

To quote a member of the language workgroup:

> [@\[Accepted with Modifications\] SE-0251: SIMD Additions](https://forums.swift.org/t/accepted-with-modifications-se-0251-simd-additions/22801/1):
>
> The [API design guidelines](https://swift.org/documentation/api-design-guidelines/) are explicit that the highest priority in library design is _clarity at the point of use_. Consistency is only a means to that end, not a goal in itself.

In my view, the existing `if case` syntax is bad. Really bad. It is incomprehensible to beginners, hard to remember for intermediates, and even experts I think will agree that it inverts the subject and object, thereby hampering code completion. It certainly does not make sense as an English sentence.

By contrast, `matches` reads fluently.

* * *

I think the best way forward is to change the current proposal to use `matches`, and either,

a. Extend this proposal to allow variable binding in `if ... matches` statements.  
&nbsp; &nbsp; _or_  
b. Plan on having a future proposal to allow it.

Either way, the destination would be a place where, instead of `if case`, people can write:

```swift
if foo matches .bar(let x) {
  // x is usable here
}

```

At that point, `if case` would be entirely superseded, `matches` would be the pattern-matching keyword that everyone knows and uses consistently, and the language would be much better for it. We would have clarity _and_ consistency, plus code completion would work in patterns.

If we’re going to make progress in this area, we should make progress in that direction.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [April 5, 2023, 3:43pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/36 "2023-04-05T15:43:51Z")

</div>

> [@Nevin](#):
>
> In my view, the existing `if case` syntax is bad.

I don't disagree, but I also don't really feel like the issues with `if case` are a result of the use of the word 'case.'

---

<div class="post-metadata">

**Author:** ![cal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cal/32/35557_2.png) [@cal](https://forums.swift.org/u/cal)\
**Post date:** [April 5, 2023, 3:45pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/37 "2023-04-05T15:45:28Z")

</div>

I think your argument in favor of using `matches` instead of `is case` is decently convincing and I can definitely support that spelling. I don't think the new syntax should support bindings though. Here's a relevant exert from the proposal document, using `matches` instead of `is case`:

* * *

These expressions could only support bindings in a very narrow context:

```swift
// We can't support bindings in general, since there isn't a scope to bind the new variables in:
HeaderView(inThread: destination matches .messageThread(let userId))

// In theory we could support bindings in if conditions:
if destination matches .messageThread(let id) {
  // Do something with `id` here
}

// But this doesn't work when combining `is case` / `matches` expressions with other boolean operators:
if !(destination matches .messageThread(let id)) {
  // `destination` is definitely not `.messageThread`, so we can't bind `id`
}

if destination matches .messageThread(let id) || destination matches .inbox {
  // `destination` may not be `.messageThread`, so we can't bind `id`
}

```

It would be confusing and inconsistent for these expressions to support different functionality depending on the context.

This functionality is already supported by `if case` statements. Love them or hate them, I think already having an exactly-equivalent language feature for doing this means it wouldn't be worth it for us to make this extremely narrow carve out in the new `is case` / `matches` expression type.

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [April 5, 2023, 4:33pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/38 "2023-04-05T16:33:11Z")

</div>

> [@Jumhyn](#):
>
> I don't disagree, but I also don't really feel like the issues with `if case` are a result of the use of the word 'case.'

Right, but the argument-for-consistency is attempting to build on a broken foundation. We should repair the foundational issue. That is, we should replace `if case` with a better syntax. (I understand we can’t actually _remove_ `if case` from the language, but we can make it superfluous, provide automatic migration, and discourage its use.)

One might suggest “`if foo is case .bar(let x)`” rather than “`if foo matches .bar(let x)`”. That is an improvement over `if case`, but I would still say that “matches” is a better fit for pattern-matching, and “is case” remains esoteric. When new people are learning, and when code is being read, “x matches y” actually describes what’s going on. It makes a lot more sense than “x is case y”. After all, the operation is pattern matching, and emphatically not case-comparison.

> [@cal](#):
>
> It would be confusing and inconsistent for these expressions to support different functionality depending on the context.

I strongly disagree. Consistently using a good syntax, which reads well and describes what is happening, is good. Someone who has learned “`foo matches .bar`” as a boolean expression, will easily understand “`if foo matches .bar(let x)`”. Consistency serves clarity here, as the wording is clear and consistent.

> [@cal](#):
>
> This functionality is already supported by `if case` statements. Love them or hate them, I think already having an exactly-equivalent language feature for doing this means it wouldn't be worth it for us to make this extremely narrow carve out in the new `is case` / `matches` expression type.

I see it differently. Because `if case` is such bad syntax, we should replace it with `if ... matches` _regardless_ of whether the current pitch is accepted. The fact that this pitch can be made consistent with that, so that `matches` is used in boolean expressions as well, is a benefit.

Put another way, if the existing spelling were already `if ... matches`, then surely the current pitch would have chosen `matches` as its keyword from the outset.

---

<div class="post-metadata">

**Author:** ![ksluder](https://avatars.discourse-cdn.com/v4/letter/k/eada6e/32.png) [@ksluder](https://forums.swift.org/u/ksluder)\
**Post date:** [April 5, 2023, 4:40pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/39 "2023-04-05T16:40:54Z")

</div>

To be clear, you’re suggesting that this pitch be blocked on overhauling the `if case` syntax throughout the language?

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [April 5, 2023, 4:45pm UTC](https://forums.swift.org/t/pitch-is-case-expressions/64185/40 "2023-04-05T16:45:52Z")

</div>

> [@ksluder](#):
>
> To be clear, you’re suggesting that this pitch be blocked on overhauling the `if case` syntax throughout the language?

No.

I am suggesting 2 things:

1. This pitch should change to use `matches`.

2. `if case` should be superseded by `if ... matches`.

Whether (2) happens as part of this pitch, or as a separate pitch, is not particularly important.

[Previous page](https://forums.swift.org/t/pitch-is-case-expressions/64185.md?page=1)

[Next page](https://forums.swift.org/t/pitch-is-case-expressions/64185.md?page=3)
