# C# Language Design Meeting for September 29th, 2025

## Agenda

- [Union Syntax Thunderdome Part 2](#union-syntax-thunderdome-part-2)
- [Enums vs Unions](#enums-vs-unions)

## Quote of the Day

- "Only this option here can have llamas in it, so that's its claim to superiority"

## Discussion

### Union Syntax Thunderdome Part 2

Champion issue: https://github.com/dotnet/csharplang/issues/9662  
Specification: https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/proposals/unions.md  
Proposals:
* https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/meetings/working-groups/discriminated-unions/allows.md
* https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/meetings/working-groups/discriminated-unions/brace-syntax.md

Today we are following up from [last time](./LDM-2025-09-24.md#union-syntax-thunderdome-part-1). We've decided that we want to have syntax outside of the body of
the union for the list of allowable cases, and today we need to decide what the initial form of that will be. This is by no means a truly final decision, and part
of the reason for front-loading this decision is so that we can get previews into user hands for feedback. We gathered a number of possible syntaxes here, though
we did not discuss the merits of every single one.

```cs
union Pet(Cat, Dog, Bird);
union Pet[Cat, Dog, Bird];
union Pet(Cat | Dog | Bird);
union Pet(Cat or Dog or Bird);
union Pet allows Cat, Dog, Bird;
union Pet includes Cat, Dog, Bird;
union Pet contains Cat, Dog, Bird;
union Pet has Cat, Dog, Bird;
union Pet with Cat, Dog, Bird;
union Pet of Cat, Dog, Bird;
union Pet switch Cat, Dog, Bird;
union Pet case Cat, Dog, Bird;
union Pet is Cat, Dog, Bird;
union Pet is Cat or Dog or Bird;
```

Broadly speaking, our ideas fall into two categories: a list surrounded by some kind of delimiter, such as `()` or `[]`, and a list started by some keyword, more
similar to generic constraint clauses. When we considered these, we also wanted to make sure we thought about them in the broader context of what a `union` type
will be able to do: have generic type parameters, constraints, implement interfaces, have a body with declarations, etc. Below are some assorted notes from
discussions of a few of these syntaxes:

* `union Pet(Cat, Dog, Bird)` looks like primary constructor syntax at first glance, will it conflict with actual primary constructors if we add them?
* `union Pet(Cat or Dog or Bird)` has a nice initial symmetry with patterns, but is that actually a good thing? If we matched on a pattern with
  `val is (Dog or Cat) dogOrCat`, `dogOrCat` isn't going to magically become an anonymous union of `Dog or Cat`, it will still be a `Pet`.
* `allows` means the opposite in C# today; it is "everything normally _and also_ ref structs". In this context, it would mean "only the types listed".
* `case` does have some symmetry with the proposed `case` classes, but those are also currently being used to actually declare a new case type. Here, it would just
  be the valid options of `Pet`, not declaring a new case.
* `is` has the same issues as the parenthesized `or` case above.

After discussion here, we have a leaning towards the first option: `union Pet(Cat, Dog, Bird)`. We do want to hear from users on this decision though, so we will make
sure to revisit this with feedback in mind to determine if that's the final form, particularly if we also decide to support primary constructors in this area.

#### Conclusion

We are moving forward with the `union Pet(Cat, Dog, Bird)` syntax form.

### Enums vs Unions

Champion issue: https://github.com/dotnet/csharplang/issues/9662  
Specifications:
* https://github.com/dotnet/csharplang/pull/9711
* https://github.com/dotnet/csharplang/pull/9713

For our second topic today, we discussed the evolution of ADT hierarchies in C#. There are two possible approaches on the table at the moment: expanding out the
`union` feature to allow declaration of cases implicitly, or expanding out the existing `enum` features to allow declaring non-numeric cases. While these both sound
dissimilar at first description, one thing that we realized after discussion is that these ideas are extremely compatible at the semantic level, with different skins
around the same general concept of having a shorthand for declaring an ADT. This is validating for the kernel of the idea itself, as no one is pushing back that this
is generally a thing that we want C# to have. However, it again puts us in a thunderdome of syntax, of `union` vs `enum`. One nicety about `enum` is that it already
has the implication that the cases are newly-declared constructs; for us to use `union` as the keyword, we'd have to either have an additional modifier on the
`union` declaration itself, or we'd have to have `case` or some similar modifier on the type declarations. The `enum` approach would also give us precedent to
expand `enum`s in other directions; [`string` `enum`s](https://github.com/dotnet/csharplang/discussions/8804), for example, are a very highly-requested item that we
have thus far avoided due in part to this issue. There is also an opportunity to use this as the point when we refresh `enum`s, allowing the declaration of other
member types that cannot exist in traditional `enum`s today.

This doesn't come without consequences. Today, `enum`s mean numbers. It's going to be a large adjustment for users if this is no longer true, and is generally a very
large shift in the way we think about these things. But we like the direction, and while we haven't settled on exact syntax (is it just `enum`? Is it `enum union`? Is
it `enum class`? Are the cases declared with `case`? and other such debates), we feel confident in this direction. We expect this to come after the `union` feature,
building on that as the way that these `enum`s get translated into actual types, but we do expect it to happen.

#### Conclusion

We will move forward with the enum-centric approach.
