meetings/2025/LDM-2025-05-12.md
Champion issue: https://github.com/dotnet/csharplang/issues/8887
Spec: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/collection-expression-arguments.md
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.
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.
Following up from last week, 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.
Projection-based approach is approved.
Also last week, 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.
with is the keyword chosen for collection expression arguments, and , is the separator.
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.
Variance is limited to explicit collection expressions, params does not perform it.