meetings/2025/LDM-2025-10-13.md
Issue: https://github.com/dotnet/csharplang/issues/9750
We started today by examining a proposed bug fix for an issue around safe contexts and collection expressions. The current behavior is a bug, but one that will cause new errors to be reported when it's fixed to reflect the specification as written. We do think that it's a worthy change though, similar in nature to the breaking change around variable scoping in loops in C# 5. We also briefly considered whether the compiler can be smarter and take the safe-context of the destination into account, but there are immediate and easy examples of where the assignment flows through multiple levels, making it hard for both the compiler and human readers to track. Given this, we will update the compiler to follow the specification as written, and will revisit if this break causes too many follow-on issues.
Break is accepted.
Champion issue: https://github.com/dotnet/csharplang/issues/9754
Specification: https://github.com/dotnet/csharplang/blob/cb0652db1e5b7cbc1b3faae61b0df9ee175b9b90/proposals/immediately-enumerated-collection-expressions.md#use-of-special-language-level-collection-type-for-immediately-enumerated-collections
Next up today, we looked at a proposal for allowing immediately enumerated collection expressions in the language. One thing that came up
immediately was that this is really 2 proposals in one; while the goal was originally just for non-observable collections to be enumerated
(in spreads or foreach), the rules end up accomplishing more as they push type inference through more locations that aren't obvious
from the title. We're concerned that there are effects beyond the examples in the specification that need to be thought through for this
inference; for example, how should array creation expressions and lambda types be affected by the type inference rules? After some
reflection, we're comfortable breaking this into two separate parts; the first is as in the title of the proposal, immediately-enumerated
collection expressions. This change would allow foreach over a collection expression, but by itself wouldn't permit spreading a ternary
of collection expressions. The rules for type inference can then be fleshed out further and the corners explored, and brought back as a
separate proposal that enables its own abilities (such as M(b ? [1, 2] : [3, 4])).
We also looked at the "type" that we want to use for these immediately-enumerated scenarios. We feel that we want to start restrictive,
and later relax restrictions, in order to protect future work in natural types. For example, if we were to say that the type of an
immediately-enumerated expression is an array, then that would permit pointer types. If we were to then choose List<T> as the natural
type of a collection expression, that would then create inconsistency on what you can foreach vs what you can assign to a var local.
Another interesting aspect is ref foreach. We think there's some thorny questions on what an interpretation of this code would be:
int x = 1;
// Does this create a copy of `x`, and `y` is a ref to that copy, or is `y` a ref to `x`?
foreach (ref int y in [x])
{
y = 2;
}
Console.Write(x);
Either interpretation is potentially confusing, so we think it's best to simply avoid the question and disallow ref foreach in this
area. After some debate, we landed on IEnumerable<T> as the type to use in foreach. It should preserve our ability to make changes in
the future without ending up in an inconsistent space, while also still allowing the implementation to do whatever efficient form it
chooses.
Finally, we looked at whether we could apply similar optimizations for foreach (var x in new[] { 1, 2, 3 }). We ultimately don't think
this is the purview of the language. There are a few types like array and List<T> that we could special case, but we can't do this in
general. The runtime has been working on escape analysis to avoid heap allocations for this type of scenario, and will continue to do so.
We think that's the appropriate place for this work to go.
Proposal is split up into immediately-enumerated collection expressions and type inference improvements for collection expressions. The
former is approved. The type of the immediately-enumerated expression will be IEnumerable<T>. We will not pursue optimizing other
types of immediately-enumerated collection creation.