# C# Language Design Meeting for May 5th, 2025

## Agenda

- [Extensions](#extensions)
    - [XML Docs](#xml-docs)
    - [Participation in pattern-based constructs](#participation-in-pattern-based-constructs)
    - [Skeleton type metadata](#skeleton-type-metadata)
    - [Single-phase consequences](#single-phase-consequences)

## Quote of the Day

- "If you change your source from release to release, which people typically do"

## Discussion

### Extensions

Champion issue: https://github.com/dotnet/csharplang/issues/8697  
Spec: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md

#### XML Docs

Questions: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#xml-docs  
Related: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/meetings/working-groups/extensions/Extension-API-docs.md

We started today by reviewing the proposed structure of XML doc comments. This review raised a few new questions as we confirmed various
components. First, should we permit overriding the `param` documentation for the receiver parameter on individual members? Our common
example, `Enumerable.cs`, does have different `this` parameter documentation throughout the file. `The source of elements to be cast` vs
`The source of elements to be filtered`, etc. However, we don't know that this is critical functionality, or that `Enumerable.cs` would
have wanted to take advantage of this if it was being rewritten from scratch today. There is already a workaround in declaring a new
extension block. This is the same workaround that we advise for other things that cannot be overridden, such as nullability annotations,
attributes, `this` parameter names, etc. Therefore, we are ok with simply adding the documentation comment to the list of things that
cannot be overridden on individual members, for now, and can revisit later if the demand for this proves itself.

Related, we also thought about the summary on the extension blocks themselves. In particular, we're not sure that this block would
actually appear anywhere in the IDE or docs experience. We want to revisit this support and make sure that we actually have a use case
for it before shipping.

Another related issue we briefly mentioned is missing documentation comment warnings; we want to make sure that adding parameter
comments to one member won't virally create missing parameter documentation comments on all the rest of the members in an extension
block; the example here would be adding parameter documentation to one member, but not having documentation on the extension parameter.
The user then gets a warning that the extension parameter is missing a comment. Then, when the user adds that comment, now every _other_
member in the block that has additional parameters is missing comments on those parameters. We need to cut off that cycle somewhere to
strike a usability balance, which will we think about and come back with.

Finally, we raised a question of how users can `cref` an extension property itself. The current design allows referring to either the
getter or setter by using the disambiguation syntax, but has no way to refer to the entire property itself. We will need to design this
and come back with a proposal.

##### Conclusion

XML approach is generally approved, with a few open questions around extension block summaries, warning virality, and property crefs.

#### Participation in pattern-based constructs

Question: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#pattern-based-constructs

Next, we took a look at what contexts we want new extensions to work in. For methods, the answer is straightforward: everywhere they
work today. For properties, it's more subtle. We wanted to start by refining the "why" of our current rules, so we can apply that why
to properties and have it naturally fall out. Roughly speaking, we generally allow extensions where the extension is not about state in
the underlying object. For example, we allow an extension `GetAwaiter`, which returns a new object that can track the state of an
underlying object and implement the `await` pattern. However, we do not then allow an extension `GetResult` on the object returned by
`GetAwaiter`, because our expectation is that the Result is intrinsic to the awaiter's state. Similarly, we do not allow extension
`Dispose`, because that is intrinsic to the state of an object. We acknowledge, however, that this principle is not universally
applied. We're not sure that we'd exclude `Slice` methods implemented as extensions today, for example, and `GetPinnableReference` is
very related to an object's state. Given this, we'll also draw from any related patterns in a given area.

We are ok with the list of areas as proposed here: allowing them in object/dictionary/`with` initializers, and property patterns. For
now, we think we should not include `Count`/`Length` properties in the determination of whether or not an object is countable, meaning
they won't participate in list patterns or in implicit `Range`/`Index` indexers. We think this because of our prior art around `Slice`,
and while we think we might want to revisit that entire space, we want to do that as a whole item, not an individual piece.

We are not settled on when delegate-returning properties will be accepted. We have conflicting prior art; `LINQ` works as a syntactic
rewrite, and thus delegate-returning properties are accepted without question. Other areas are not syntactic rewrites, and do not
accept delegate-returning properties. More thought needs to go into the space before we can make a decision.

##### Conclusion

New extensions methods will behave like old extension methods in pattern-based locations. Extension properties will participate in
in object/dictionary/`with` initializers and property patterns for now, with further expansion on the table for later.

#### Skeleton type metadata

Question: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#namingnumbering-scheme-for-skeleton-type

Public API tools that verify our unspeakable extension metadata have an issue with how we currently decide on names. Our current
approach has some issues around determinism that we need to address, but even if we adjust this, it seems very likely that the public
API validation tools are going to need to adjust. We don't think that we consider the names of the skeleton structures to be
part of the API; they're not referred by implementations, and purely exist for the compiler to be able to understand underlying
structure. We don't think there's a naming structure that we can come up with that won't run into collisions of some kind unless we
have an incrementing number somewhere, which would then break if something is reordered. Given this, we believe the tool will still
need to update to understand when the name isn't important.

##### Conclusion

The compiler algorithm does need to be double-checked and verified, but we expect tooling that validates public APIs from release to
release will need to update as well.

#### Single-phase consequences

Question: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#new-generic-extension-cast-method-still-cant-work-in-linq  
Related: https://github.com/dotnet/roslyn/issues/78415

Finally, we looked at an outcome of moving back to single-phase generic resolution. The BCL had been hoping to fix an issue with
`Cast<TSource, TResult>` on `IAsyncEnumerable`, where since `TResult` cannot be inferred from the parameters, both generic type
parameters must be explicitly supplied, so things like `from Type t in asyncEnumerable`, which gets translated into
`asyncEnumerable.Cast<Type>()`, cannot work due to differing arity. The first thing we considered was whether LINQ could do something
about this, potentially specifying both type parameters in this case. We think that would be especially difficult given the current
structure of query expressions; they're defined as pure syntactic rewrites, not involving semantics. This fallback would have to be
based on semantic information.

We also briefly talked about two-phase inference again. We do think that this scenario is something that we want to support in the
language, but as in previous LDMs, we don't think that this limitation is specific to extensions. Instead, we want to investigate a
more general approach that can work regardless of extension-ness.

##### Conclusion

This is not the straw that breaks the camel's back. We will continue to investigate what we can do to make this scenario better in
general.
