# C# Language Design Meeting for August 27th, 2025

## Agenda

- [Type inference in patterns](#type-inference-in-patterns)
- [Type value conversion](#type-value-conversion)
- [Union syntax](#union-syntax)

## Quote of the Day

- "Boiled frogs taste delicious." "Not if you're the frog."

## Discussion

### Type inference in patterns

Champion issue: https://github.com/dotnet/csharplang/issues/9630  
Specification: https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/proposals/inference-for-type-patterns.md

First up today, we looked at the next proposal in the list for type inference improvements. These proposals arise from
the general unions discussion but can also be useful outside of unions. In this case, we're looking at type inference
inside patterns. Unlike the previous two proposals, which were easier sells, LDM is more skeptical about this one. In
particular, type inference has more latitude for patterns than it does for constructor calls, since you can start with a
base type and narrow to a derived type. In constructors, the `new` must refer to something that either is the same type
as the target, or has a direct conversion to the target. In patterns, that isn't the case. You can have a pattern that
downcasts, upcasts, or checks a completely unrelated interface, which affords much more freedom. We also know of users who
will explicitly state types to serve as a `null` check in their patterns, even if that's an identity conversion. There are
mitigations though: if a user has a generic type in hand and they're pattern matching on it, we think it's unlikely that
they would upmatch to the non-generic base rather than to a more derived type. The main scenario we can think
of in this category would be something like:

```cs
IEnumerable<string> e = ...;
if (e is IList) { ... }
```

Under the current proposal, this would continue to match `System.Collections.IList`, and not infer
`System.Collections.Generic.IList<string>`, but should it? Would we consider breaking this behavior? There's also concern
that it may be surprising that a pattern, which is supposed to match against a type, might do type inference that isn't
immediately visible at the pattern site.

One potential option would be to always require some sigil or syntax to inform both the compiler and the user that inference
is happening and expected. For example, `Type<>`. This particular syntax didn't immediately resonate with everyone though;
a few LDT members preferred no syntax at all, and others felt that it might be confusing given that open types in `typeof`
require commas to differentiate how many omitted type parameters exist.

Another topic we briefly considered was whether to push inference further. An `is Type` check is effectively an `as`
combined with an immediate `null` check, and an `as` is just one form of cast. Should both `as` casts and hard casts also
support this? It seems reasonable that if `option is Some` would benefit, `(Some)option` would similarly benefit.

#### Conclusion

We came up with more questions than answers. This will need further investigation; we see value in the proposal, but
we need to think about it more.

### Type value conversion

Champion issue: https://github.com/dotnet/csharplang/issues/8928  
Document: https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/meetings/working-groups/discriminated-unions/type-value-conversion.md

Next, we looked at yet another union-related proposal, this time on allowing type expressions to be directly converted to
instances. While we think this is useful for singleton union cases, we also think it has applicability outside of unions.

We think there are at least three approaches we can take to this problem:

1. A conversion, as specified right now. The main disadvantage of this is that conversions generally can't happen in the
   middle of a dotted expression, except on extension receivers. The advantage, though, is that we don't need to solve
   a new `Color Color` problem, since we wouldn't be introducing a new spot where type and instance confusion can occur.
2. Allowing users to define a property with the same name as a nested type. This is the real root of the specific problem
   that this proposal is solving: we want to allow things like `Option<T>.None` as a value. If that was just a property with
   the same name as the nested type, then it would work fine. That would give us a new instance of the `Color Color`
   problem, though, as we'd need to determine, every time we see `Option<T>.None`, whether `None` refers to the property or
   the type.
3. Introduce a general operator for this (not a conversion) that can occur in the middle of dotted expressions. This would
   also require us to solve the general `Color Color` problem, but it is more generally useful than option 2 for non-nested
   singleton types.

After discussion, we preferred option 3: it's the most generally useful and can solve this for both nested and non-nested
types. There are still plenty of design decisions to make, but we like the direction.

#### Conclusion

We'll work on specifying option 3 more completely.

### Union syntax

Champion issue: https://github.com/dotnet/csharplang/issues/9411  
Union overview issue: https://github.com/dotnet/csharplang/issues/8928  
Specification: https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/proposals/nominal-type-unions.md

Finally, we took a brief look at our union syntax again. A few members of the LDM and some members of the community are not
satisfied with the current `union Pet(Cat, Dog, Bird);` syntax. Much of the current concern can be summarized as "it looks
like a primary constructor that implies order, which it's not." One thing we want to make sure of is that we're not
over-indexing on making new syntax stand out; is this a real consistency issue, or is this just an initial confusion that
will fade with usage? We brainstormed a few other syntax options:

1. The original: `union Pet(Cat, Dog, Bird);`
2. Using bars: `union Pet(Cat | Dog | Bird);`
3. Using or: `union Pet(Cat or Dog or Bird);`
4. Using enum bodies:
```cs
union Pet
{
    Cat, Dog, Bird
}
```

Option 2 received little support. Option 3 provides a nice symmetry with how consumption in patterns will be structured.
Option 4 has a nice symmetry with enums and potentially provides a single syntax we could use for defining members on both
unions and enums. We didn't make a decision today, but we do think it's clear that there's enough here to warrant revisiting
the syntax decision.
