# Syntactic sugar for union cases in match statements

**URL:** <https://discuss.python.org/t/syntactic-sugar-for-union-cases-in-match-statements/49274>\
**Category:** Ideas\
**Created:** [March 23, 2024, 9:30am UTC](https://discuss.python.org/t/syntactic-sugar-for-union-cases-in-match-statements/49274 "2024-03-23T09:30:54Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![tmk](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tmk/32/10935_2.png) [@tmk](https://discuss.python.org/u/tmk)\
**Post date:** [March 24, 2024, 3:48pm UTC](https://discuss.python.org/t/syntactic-sugar-for-union-cases-in-match-statements/49274/4 "2024-03-24T15:48:59Z")

</div>

> [@NeilGirdhar](#):
>
> Isn’t this extremely niche? Is it very often the case that two child classes have matching members?
> 
> Anyway, isn’t this also an unnecessary restriction if you use keyword arguments in the case statement? If you’re going to go this route, then all of the keywords passed to the case statement just need to be an intersection of the members for each element of the union.

Right, it probably makes sense to make this less strict. The following seems pretty safe:

```python
from typing import NamedTuple, TypeAlias

class A(NamedTuple):
    x: int # only `x` this time

class B(NamedTuple):
    x: int
    y: str

AB: TypeAlias = A | B

match ab:
    case AB(x): # only `x`
        print(f"{x=}")

```

as syntactic sugar for

```python
match ab:
    case A(x) | B(x, _): # note the wildcard usage
        print(f"{x=}")

```

which would work as long as all the ` __match_args__ ` start with an identical sequence.

And then you could loosen it even further by allowing different names in the ` __match_args__ `:

```python
class A(NamedTuple):
    x: int

class B(NamedTuple):
    x: int

AB: TypeAlias = A | B

match ab:
    case AB(x):
        print(f"{x=}")

```

That’s probably also fine, though it could lead to hard-to-notice bugs.

> [@NeilGirdhar](#):
>
> I think it would also help if there were motivating examples that match against `AB`. And for each example, to compare the case where `type AB = A | B` with having `AB` as explicit base class.

I’m not sure I’m understanding correctly, but to re-iterate, the main motivation is as an alternative to the [sealed class proposal](https://discuss.python.org/t/draft-pep-sealed-decorator-for-static-typing/49206); as an alternative way of making static exhaustiveness checks work for subclasses.

We can of course define it like this:

```python
@dataclass
class AB: ...

@dataclass
class A(AB):
  x: int

@dataclass
class B(AB):
  x: int

ab: AB = A(3)

match ab:
  case AB(x):
    print(f"{x=}")

```

This works, but then when we want to distinguish `A` and `B`, static type checkers will complain:

```python
match ab: # match is not exhaustive
  case A(x):
    print("this is A")
  case B(x):
    print("this is B")

```

So, we would like to use the type `A | B`, so that exhaustiveness checking works, but when we do that and use a type alias of `A | B` everywhere, we encounter the problem that you can’t use that type alias as a `case:`, which is something you might sometimes want to do.

```python
class ExpressionBase:
    def shared_functionality(self): ...

@dataclass
class Name(ExpressionBase):
    name: str

@dataclass
class Operation(ExpressionBase):
    left: "Expression"
    op: str
    right: "Expression"

Expression: TypeAlias = Name | Operation

def f(node: Expression | Statement):
    match node:
        case Expression(): # we want to match on any `Expression` here
            print("it's an expression")
        case Statement():
            print("it's a statement")

def g(expr: Expression):
    match expr:
        case Name(name):
            print(f"{name=}")
        case Operation(left, op, right):
            print("it's an operation")

```

Hmm, typing out this example, it seems that it’s in practice probably most useful to use the union type alias in a `case` that does not bind any variables.

So, we should definitely do the thing where it’s fine when all the ` __match_args__ ` aren’t perfectly identical.

---

_[View the full topic](https://discuss.python.org/t/syntactic-sugar-for-union-cases-in-match-statements/49274)._
