meetings/2025/LDM-2025-12-17.md
Champion issue: https://github.com/dotnet/csharplang/issues/8887
Spec: https://github.com/dotnet/csharplang/blob/01e436bf45790b7118c116100c27a8172148c58d/proposals/collection-expression-arguments.md#finalizing-an-open-concern-from-httpsgithubcomdotnetcsharplangblobmainmeetings2025ldm-2025-03-17mdconclusion
We started today by revisiting an earlier temporary decision; when we were considering whether with would be a breaking change at the
top level for collection expressions, we initially decided that we would take the breaking change for preview, but since we hadn't yet
finalized our syntax and were planning on previewing it for .NET 10, we didn't want to potentially break users for syntax we weren't certain
of. Since then, we've had our debates, settled on with as the syntax, and now we want to revisit the breaking change downlevel. Our
default approach to parsing changes is to always parse with new language features, and issue errors when users don't have the appropriate
language version enabled. Searching through GitHub we are unable to find examples of code that will actually break in this, so we are
comfortable following our usual approach; the .NET 11 SDK/C# 15 compiler will always parse with as collection expression arguments,
regardless of the language version of the project.
We also wanted to talk about the formal definition of the feature, and in particular, how the grammar rules actually will work. Do we want
to have a rule where the with has to be the top-level expression in the collection expression element, or do we want a rule where, if we
encounter with( to start a collection expression element, that element is a with element, regardless of following content? Concretely,
the question is how do we want something like this to parse: [with() + with()]. With the top-level rule, this would just be a binary
operator + with method calls to methods named with in either arm. With the "first token" rule, it would be a with element, followed by a
binary operator + whose left operand is missing, and the right operand is a method invocation named with. After some debate, we decided
that it is simpler to go with the "first token" rule, and matches our precedent with spread elements, where a .. always starts a spread,
never a range. This makes the parsing simple, and parentheses can easily disambiguate for scenarios where the user really wants to call a method,
just like it works for range.
We will not take language version into account when parsing, and will always parse with elements as with elements. If a collection expression
element starts with with(, that means it is a with element, following the .. spread precedent.
Issue: https://github.com/dotnet/roslyn/issues/7502
Spec: https://github.com/dotnet/csharpstandard/blob/41694caebb0fb759b75ef66b9d11d37006aab000/standard/expressions.md#12813-null-conditional-element-access
Next up, we discussed a potential compiler bug/specification bug. This has been open for a long time, but was recently resurfaced and we wanted to
investigate to clarify our definitions. The question hinges on what the definition of what a non-nullable value type is. If a pointer is a non-nullable
value type, then the rules as written state that the type would have to be Nullable<int*>, which is indeed illegal. But if pointers are not
non-nullable value types, then the cases would fall through to the last bullet of the spec and it should just work, as the specified transformation
would be legal for a pointer. Certainly on the surface, pointer types are nullable: int* i = null; is legal, as is comparing them with null. Given
that, and the definitions in §8.2.1,
we are comfortable treating this as a compiler bug, and will fix it to work. We will also leave the decision on clarifying the specification further
to the ECMA 334 committee.
Null-conditional expressions that produce a pointer type not being allowed is a compiler bug and will be fixed as such.
Finally today, we did some triage on newly-championed issues over the past few months.
Champion issue: https://github.com/dotnet/csharplang/issues/9803
Spec: https://github.com/dotnet/csharplang/blob/e878e7860d9b6420112fd7b99b910a79c7103132/proposals/top-level-members.md
There are some strong feelings on this one in the LDM; nothing that we think would hold us from doing a deep design dive on it, but by no means is there agreement on the feature at this point. We'll put it into the working set to have that debate.
Champion issue: https://github.com/dotnet/csharplang/issues/8606
Spec: https://github.com/dotnet/csharplang/blob/afad49721a7b9923efbbc36ae6c455d85b994543/proposals/using-with-a-discard.md
Finally, we looked at a proposal for creating using local declarations without actually having to declare a local, marrying the implicit scope
benefits of using locals with the lack of variable pollution available from using statements. We are interested, but want to rename the proposal
from the current state to better reflect that goal, rather than a specific implementation of achieving that goal.