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

## Agenda

- [Collection expression arguments](#collection-expression-arguments)
    - [Empty argument lists](#empty-argument-lists)
    - [Constructor binding behavior](#constructor-binding-behavior)
    - [Syntax](#syntax)
- [Dictionary expressions](#dictionary-expressions)

## Quote of the Day

- "Why would you say that?" "Look, hubris is my thing" [much later] "Hey, I didn't jinx it after all!"

## Discussion

### Collection expression arguments

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

#### Empty argument lists

Question: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/collection-expression-arguments.md#empty-argument-lists

First up, we looked at when to permit empty argument lists. We want a simple rule here, something easy to explain to users. One option is just "allowed for everything", which is
certainly easy to explain. However, it may run into friction in the spec and compiler; what does it actually mean, particularly for arrays and spans? Neither of those have a
traditional "constructor" that can accept arguments, so what does the `with()` actually bind to? Another simple option is to permit it when there exists a constructor or `Create`
method that can accept the empty argument list. For such a rule, the main question is then whether interfaces can accept an empty argument list. We think this might be slightly
more common than for arrays or spans; it is reasonable for an API author to move from a specific type to an interface to abstract things in a breaking update or internally. It
would mean that we would need to amend the list of accepted constructors for interface types to include the empty constructor as well, but that seems reasonable. A final option
would be to simply disallow an empty `with()` entirely, but that feels too heavy-handed; being explicitly about not passing arguments is a perfectly reasonable thing to do.
Therefore, we will allow `with()` for constructor types and builder types that can be called without arguments at all, and we will add empty constructor signatures for the
interface types.

##### Conclusion

We will allow `with()` for constructor types and builder types that can be called without arguments at all, and we will add empty constructor signatures for the
interface types. Arrays and spans will not allow `with()`, as there are no signatures that would fit them.

#### Constructor binding behavior

Question: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/collection-expression-arguments.md#collectionbuilderattribute-methods

Following up from [last week](./LDM-2025-05-07.md#constructor-binding-behavior), we're revisiting the rules for create method binding. We have a new proposal that regularizes
the approach by creating projection signatures: chopping off the last parameter of the builder method, then doing standard overload resolution rules, creating a signature that
is similar in approach to a constructor signature for types that use constructor-based creation. This does nicely regularize the approach, and solves the questions around which
ROS to use if multiple are in a signature, but does still present the question of what do users do to use optional parameters? After some discussion, we've hit on the mental
model that users are likely to not know exactly what they're calling: a `Create` method, a constructor, a synthetic constructor for an interface, they all appear the same from
a mental model perspective. The projection also fits in with that model, and that's what we intend to proceed with.

##### Conclusion

Projection-based approach is approved.

#### Syntax

Also [last week](./LDM-2025-05-07.md#syntax), we had 2 syntax choices to finish on: whether to use `;` or `,` as the separator for collection arguments, and whether to use `with`
or `args` as the keyword. We did very little discussion today, and instead went straight into a read of the room. This revealed that, while there is still some support for both
`;` and `init`, both are in the minority. We will approve `with(),` as the syntax for collection expression arguments.

##### Conclusion

`with` is the keyword chosen for collection expression arguments, and `,` is the separator.

### Dictionary expressions

Champion issue: https://github.com/dotnet/csharplang/issues/8659  
Spec: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/dictionary-expressions.md#support-keyvaluepair-variance-with-params

Finally today, we took a look at a question in dictionary expressions: should we support KVP variance in `params`. This pulls in two directions: as a bare parameter, KVP has no
variance. However, if the user were to surround the provided `params` argument with a collection expression, it would start to work. We've further said in the past that we want
to try and minimize the differences between what collection expressions can do, and what `params` can do.

That being said, there are also good arguments for disallowing this. The general idea behind `params` is that the user doesn't know that they're calling something that accepts
a collection, and they get the same experience they'd get if they called a method that just had a signature with however many parameters they provided. There are also other
aspects of collections expressions and `params` that differ, such as extension `GetEnumerator`. We also aren't adding generalized KVP variance; it's specifically a feature of
collection expressions. We therefore think we should keep it limited to just collection expressions.

#### Conclusion

Variance is limited to explicit collection expressions, `params` does not perform it.
