# C# Language Design Meeting for October 2nd, 2024

## Agenda

- [Open questions in field](#open-questions-in-field)
    - [`readonly` contexts and `set`](#readonly-contexts-and-set)
    - [`Conditional` code](#conditional-code)
    - [Interface properties and auto-accessors](#interface-properties-and-auto-accessors)
- [Extensions](#extensions)

## Quote of the Day

- "Attempting to find my way to this room was like navigating the Severance basement"

## Discussion

### Open questions in field

Champion issue: https://github.com/dotnet/csharplang/issues/140  
Questions: https://github.com/dotnet/csharplang/blob/3cca17a650e40d787629e52a8d46e59459cb2b74/proposals/field-keyword.md#open-ldm-questions

#### `readonly` contexts and `set`

There could be scenarios for this where you're implementing a `set` accessor on a `readonly` struct and either passing it through, or throwing. Recommendation is accepted, we will
allow this.

#### `Conditional` code

`Conditional` code can have effects on non-conditional code, such as `Debug.Assert` changing nullability. It would be strange if `field` didn't have similar impacts. It is also
unlikely to come up in most code, so we'll do the simple thing and accept the recommendation.

#### Interface properties and auto-accessors

Standardizing around the instance field itself being the cause of the error is consistent with partial properties in classes, and we like that outcome. The recommendation is accepted.

### Extensions

Champion issue: https://github.com/dotnet/csharplang/issues/5497  
Related: https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/extensions-as-static-types.md, https://github.com/dotnet/csharplang/pull/8472

Today, we continued our thinking around extensions from [last time](./LDM-2024-09-30.md#extensions), and around how we want to approach the complex issues standing in the way of
us getting previews out. Unfortunately for us, this ended up raising far more questions than answers. The focus today was around aligning with method type inference for existing
extension methods. As an example:

```cs
public class C
{
    public void M(I<string> i, out object o)
    {
        i.M(out o); // infers E.M<object>
        i.M2(out o); // error CS1503: Argument 1: cannot convert from 'out object' to 'out string'
    }
}
public static class E
{
   public static void M<T>(this I<T> i, out T t) { t = default; }
}
public static extension E2<T> for I<T>
{
   public static void M2(out T t) { t = default; }
}
public interface I<out T> { }
```

As currently envisioned, extension types have a 2-stage type inference approach. The first stage deduces the type parameter for the extension type, based on the receiver, and the second
deduces any type parameters on the method (if there are any). This is very different to how today's extension methods work; since all type parameters are on the method, they're all inferred
at the same time, and the receiver is just one of the parameters. This is an example of a behavior difference that we'd incur between old and new extension methods, and we want to see if
we can solve it. One possibility is a single pass, that pretends the type parameters from the extension type are part of the method signature. Then we do the same single pass as in extension
methods today, and it all behaves the same.

This comes with its own downsides, however, which is breaking a _different_ expectation from C# users around how type parameters work. There is no place in C# today where type parameters
from different definitions are smashed together and inferred at the same time. A single-stage inference pass will look and feel different to how the syntax implies that it would work. Some
members feel that the two-stage approach is the more logical approach in general, and actually appreciate that VB did this with classic extension methods.

We then further got into discussions around compat, and how/if existing extensions methods could move to the new form. As an example, could `LINQ` be written in the new form? We're somewhat
concerned that it couldn't be, at least not as designed today; there's an `Enumerable` class with a large number of extensions in it, many on differing types. Adopting the new form would
of course at least break binary compat, since we can't define all those methods in a single extension type. We'd then further be concerned that this would block the BCL from using the new
form in conjunction with the old form, due to concerns about the differing inference methodology, as well as other behavioral differences between the forms.

This has finally brought us squarely back to the questions on syntax. If the current syntax implies a particular behavior, and that behavior would block adoption, perhaps a different form
is needed. We could consider a more member-centric approach, rather than a type-centric approach. We're definitely not ready to make any calls on this today, but we shall examine these ideas
further in the next LDM.
