# C# Language Design Meeting for March 17th, 2025

## Agenda

- [Collection expression arguments](#collection-expression-arguments)
    - [`with` breaking change](#with-breaking-change)
    - [Collection expression arguments and conversions](#collection-expression-arguments-and-conversions)
- [Dictionary expressions](#dictionary-expressions)
- [Extensions](#extensions)
    - [Accessibility](#accessibility)
    - [Static factory scenarios](#static-factory-scenarios)

## Quote of the Day

- "I hope no one was confused by me saying coversion instead of conversion" "Contraversion"

## Discussion

### Collection expression arguments

Champion issue: https://github.com/dotnet/csharplang/issues/8887  
Specification: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/collection-expression-arguments.md

#### `with` breaking change

Question: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/collection-expression-arguments.md#with-breaking-change

We started today by looking at whether, and if so where, to take a breaking change around the meaning of `with()` in a collection
expression. We don't want `[with(1), with(2)]` to have different meanings for what `with` binds to, so we're ok with a breaking change
in general. However, we haven't yet had the in-depth debate on whether `with` is the final syntax; given this, we don't want to risk
anything on lower language versions at this time.

##### Conclusion

We will take the breaking change around `with` inside a collection expression, but only in language version preview for now.

#### Collection expression arguments and conversions

Question: https://github.com/dotnet/csharplang/blob/753119dee9eb5e5a4bd36072559b25d9064c63e6/proposals/collection-expression-arguments.md#should-arguments-affect-collection-expression-conversion

We think that the precedent around `new()` is good here. It's possible that we could relax the language here in the future, but we think
that if we do so, it should be done holistically, for both `new()` and collection expressions, rather than just for collection expressions.
`new()` doesn't do this because of the concern that it would mean adding a new constructor to a type could become a source-breaking change,
and we think that we'd have to delve into that concern for both constructs at the same time.

##### Conclusion

Collection expression arguments will not be used as part of determining whether a collection expression conversion exists.

### Dictionary expressions

Champion issue: https://github.com/dotnet/csharplang/issues/8659  
Specification: https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md
Question: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/dictionary-expressions.md#conversion-from-expression-element-for-keyvaluepairk-v-collections

Following up from [last time](./LDM-2025-03-05.md#dictionary-expressions), the working group brought a proposal around key/value pair
conversions in dictionary expressions. We're a bit concerned about the broad applicability of the proposed rules: they block off
user-defined conversions when the iteration type is a KVP, even if we're not converting to a dictionary expression. That seems wrong to
us; the user indicated how to convert a given type to a KVP, so why would we ignore that information? Our desire for covariance in KVP
does make this more complicated than a standard conversion though. For example, what if the type specifies 2 UDCs to different KVP
instantiations? Which one would we prefer for a variance conversion to the iteration type? After some discussion, we think that such
"multiple conversion path" types are a sufficiently small corner of a corner that we don't have to worry about it: either better conversion
will return an exact conversion to the element type of the collection expression, or we'll get an ambiguity.

We also briefly re-examined whether we actually want to support these variance scenarios outside of pure dictionary types, and our
conclusion is that we do. There are thousands of examples of `IEnumerable<KeyValuePair>` APIs on GitHub, for methods that take any form
of dictionary or list of KVPs, and we would like to support simple syntax for such APIs.

##### Conclusion

We will allow all standard element type conversions that we allow in normal collection expressions when the element type is a KVP. We will
allow KVP covariance in all collection expressions.

### Extensions

Champion issue: https://github.com/dotnet/csharplang/issues/8697  
Specification: https://github.com/dotnet/csharplang/blob/b484275c4369638c2c5f9305716582c76a1c9335/proposals/extensions.md

#### Accessibility

Question: https://github.com/dotnet/csharplang/blob/b484275c4369638c2c5f9305716582c76a1c9335/proposals/extensions.md#accessibility

First up today, we continued from [a previous LDM](./LDM-2025-03-10.md#accessibility) on the topic of accessibility. We think our initial
gut feeling was correct; extension blocks are not real items. You can declare multiple extension blocks for a single type, would `private`
be private just to a single block, or to all shared blocks? There are also other decisions that we'd need to revisit if we started giving
blocks a stronger identity here.

##### Conclusion

Accessibility in extension blocks is relative to the containing static class.

#### Static factory scenarios

Question: https://github.com/dotnet/csharplang/blob/b484275c4369638c2c5f9305716582c76a1c9335/proposals/extensions.md#static-factory-scenario

The working group took a look at the [previous decision](./LDM-2025-03-03.md#static-method-overloading) around static method overloading,
and has come to the conclusion that there are current technical limitations around `modopt`/`modreq`s in the compiler that would make using
them to permit overloading here difficult; today, Roslyn does not support using anything but a named type in a `modopt` or `modreq`. This
is a compiler restriction, not a runtime restriction, but would be a somewhat involved change to fix up. However, we're also questioning
whether we should support this type of overloading at all in extensions: sure, we can figure out how to emit such methods, but what would
the disambiguation syntax be? We've already walked back from adding new syntax in other places for this, and while we do think that the
scenario where a user wants to define the same static method on several types isn't unreasonable, we also think that we might be able to
start restrictive for a preview period, and then listen for feedback.

##### Conclusion

We will enforce standard overloading rules across extension blocks, so static methods on different underlying types in the same static class
will not be able to share the same name and parameter types.
