# C# Language Design Meeting for June 11th, 2025

## Agenda

- [Extensions](#extensions)
    - [Dynamic resolution of operator `true`/`false`](#dynamic-resolution-of-operator-truefalse)
    - [Extension operators in LINQ expression trees](#extension-operators-in-linq-expression-trees)
    - [Built-in operator protection rules](#built-in-operator-protection-rules)
    - [Extension module initializers](#extension-module-initializers)
    - [Extension methods as entry points](#extension-methods-as-entry-points)
    - [Langversion behavior for new extensions](#langversion-behavior-for-new-extensions)
    - [`nameof`](#nameof)

## Quote of the Day

Nothing particularly amusing was said today, sorry.

## Discussion

### Extensions

Champion issue: https://github.com/dotnet/csharplang/issues/8697  
Specifications:
* https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md
* https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md

#### Dynamic resolution of operator `true`/`false`

Question: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md#dynamic-evaluation

We think the proposed restriction makes sense. The C# spec says that when one or both operands of a binary operator is dynamic, the entire operation, including lookup of
operator `true`/`false`, occurs at runtime. The compiler performing the lookup at compile-time for operator `true`/`false` for the non-dynamic operand is an optimization, nothing
more, and the dynamic binder would not be able to find extension `true`/`false` operators, just as it can't find instance extension methods today.

##### Conclusion

Restriction accepted. Extension operator `true`/`false` are not used for `dynamic` `&&` or `||`.

#### Extension operators in LINQ expression trees

Question: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md#use-of-extension-operators-in-linq-expression-trees

The proposal was accepted without further discussion beyond what is in the question itself.

##### Conclusion

Accepted.

#### Built-in operator protection rules

Specification: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md#is-the-rule-an-extension-operator-may-not-have-the-same-signature-as-a-predefined-operator-worth-having-as-specified

Further testing of our proposed rules for protecting built-in operators has revealed holes in our proposal, namely when conversions to built-in types are involved, bypassing
the existing rule. While we could create a more complicated rule to address this, involving overload resolution, we don't like the end result: it's a complicated rule that we
don't feel carries sufficient weight to justify the complexity. We could reduce this to a warning instead, and conceptually don't have an issue with it, but we don't
think that such a warning must be present; we think that when a predefined operator is chosen over an extension operator, it will be fairly obvious what is happening.

##### Conclusion

Rule is abandoned. We will not have built-in errors or warnings here.

#### Extension module initializers

Question: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#open-issues

The question here is whether to permit extension implementation members to be module initializers. We don't have any motivating scenarios here and don't have a proposal
for how the attribute would be applied to either skeleton or implementation members. Therefore, we will reject this until we have motivation to implement it.

##### Conclusion

Rejected.

#### Extension methods as entry points

Question: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#open-issues

We must keep the implementation methods for instance extension methods as entry point candidates, as it works today and we have a strong back-compat goal here. Therefore,
we intend to continue permitting methods that end up having an implementation method with a valid entry point signature to be considered in the set of possible entry points.

##### Conclusion

Implementation methods that have a valid signature will be considered among the possible entry point candidates.

#### Langversion behavior for new extensions

Question: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#open-issues

After some consideration, we don't think we need to have lookup consider language version for the actual lookup process itself. The scenarios in which a user could
run into issues are:

* A delegate-returning property gets ahead of an old-style extension method, so `obj.M()` becomes an invocation of the delegate returned from the property `M`.
* A method group used as an assignment/argument gets superseded by an extension property, so `M(e.MethodGroup)` goes from a method to a property.

In either of these cases, we will issue a LangVersion diagnostic but won't otherwise complicate lookup with exceptions around excluding new-style extensions. The main
concern is that we can't issue a diagnostic for instance extension methods, since you can already have them today and going from old to new style is not otherwise a breaking
change.

##### Conclusion

We will issue LangVersion diagnostics on successful lookups/overload resolutions that pick a non-instance extension method.

#### `nameof`

Question: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#nameof

Finally today, we took a look at `nameof` rules. There's a bit of tension here: we want to allow referencing an extension property in a `nameof`, but we want to be
consistent with current rules around extension-based lookup in `nameof`. Today, extension methods cannot be referenced in `nameof` off their extended type or an instance
of their extended type. They must be looked up on the extension container. This restriction was mostly about cutting design time to get extension methods shipped, and we're mixed
on whether to keep it long term. We don't think that this is the entire solution though, as ambiguity once again raises its head. We came up with 3 main approaches to the
lookup:

1. `ExtensionContainer.extension(param).Member` - Essentially borrow the cref syntax. We think this is too heavy-handed for just `nameof` and want to avoid it.
2. `ExtendedType.Member` - Allow this form and likely lift the restriction on all extension members. Do nothing to provide disambiguation syntax.
3. `ExtensionContainer.Member` - Simply make this lookup work, even for extension properties and events.

We think we want option 3; it's the most consistent with the current approach and ensures that there isn't multiple ways to reference the member. At the same time, though,
we know that we likely will not have time to design and implement this lookup for C# 14; after design, we may even decide that we don't like how the rules turn out and need
to go back to the drawing board. Given this, we've decided that we will likely not support `nameof` on extension properties for C# 14. We will revisit and take up
the design pen again as soon as we can here, but do not want to jeopardize shipping the feature over `nameof` support.
