# C# Language Design Meeting for October 2nd, 2023

## Agenda

- [Collection expressions](#collection-expressions)

## Quote(s) of the Day

- "Can I add a 4th bullet? Don't design it now, do it now" "This isn't a Punnett square"
- "Ok, that was three deep breaths" "I only did 2" "I have small lungs, what can I say"
- _<redacted> posts a picture of the IEnumerable hierarchy_ "Thank you, <redacted>, that was... horrifying. Horrifying and super useful"

## Discussion

### Collection expressions

https://github.com/dotnet/csharplang/issues/5354  
https://github.com/dotnet/csharplang/issues/7542

Today, we looked at how the conversion for collection expressions is defined for `IEnumerable` types. This is the rule that allows collection expressions to be fully
compatible with types that can be initialized by a collection initializer today; because of this broad compatibility, it has some issues that we think may cause the feature
to be brittle in the face of user interaction. Specifically, determining whether the conversion exists requires the compiler to attempt to bind the call to the constructor,
and every `Add` or `AddRange` call, before determining that a conversion exists. This can potentially lead to unstable behavior in the editor in the face of user errors, and
it's a problem we've seen before. In particular, interpolated string handlers were originally specified this way, but we revised the specification after considering this issue.
We are therefore considering updating the spec here to avoid the same problem. The new rules do have a marked disadvantage: they aren't fully compatible with all types that
can use a collection initializer types today. If there are extension `Add` methods that convert inputs to the element type of the collection, they would not be considered by
this new rule. We do expect that these cases are somewhat rarer though, and that we can address this later if it becomes a problem.

These rules also prompted a discussion on support for non-generic `IEnumerable`. The WG was unclear on the exact outcome from a
[prior LDM](LDM-2023-08-09.md#target-typing-of-collection-expressions-to-core-interfaces), and whether the non-generic `IEnumerable` and descendent interfaces (such as `ICollection`)
need to be supported for target-typing as well. We clarified that we don't think we can make a decision about whether to consider the non-generic `IEnumerable` "deprecated" by
ourselves; it would need to be a larger decision among all the .NET teams. We also don't think supporting the non-generic types will cause any new ambiguities that didn't already
exists: for example, if an API is overloaded on `ICollection` vs `ICollection<object>` today, it's already ambiguous, because `ICollection<T>` doesn't inherit from `ICollection`.

As part of this consideration, we also confirmed that we do want to be able to target the non-generic interfaces with collection expressions. IE, this should work:

```cs
ICollection c = ["a", 2, null];
```
However, we think we may not be able to get this in C# 12, and it may have to wait for C# 13 and be considered in tandem with natural types for collection expressions.

Finally, we thought about how the new rules apply to `string`s. There are two core scenarios to think about here:

```cs
// Scenario 1
void M1(string s) {}
void M1(ReadOnlySpan<char> r) {}
M1(['a', 'b', 'c'])

// Scenario 2
void M2(string s);
void M2(char[] characters);
M(['a', 'b', 'c']);
```

Scenario 1 is extremely realistic, and in fact already exists in the BCL. We'd much prefer that it call the `ReadOnlySpan` API, which does not need to allocate; the `string` API
needs an instance of a `string`, which could very well allocate if the items were not constant. To accomplish this, we need to update the betterness rule from a
[previous LDM](LDM-2023-09-20.md#overload-resolution-fallbacks) to consider `Span` better than both array _and_ `string`, or it will become ambiguous.

The second API, though, is not ambiguous by today's rules, as `string` is not constructable and therefore no conversion exists. By the new rules though, `string` is a valid
target type for collection expressions, and will simply fail at a later stage. This makes the `M2` API ambiguous. After some more consideration, we think that there's good
reasoning for making `string`s constructable with collection expressions. List patterns already work on them, and we think that syntax could be useful for combining multiple
string slices together. Support for this, though, is likely not going to make C# 12, and will be considered for future C# versions.

#### Conclusions

The proposed change to the collection expression rules is adopted as worded.  
Collection expressions can be converted to `string`s, though the conversion will fail to compile today. We will hope to make it work in the future.  
We update the overload resolution betterness rules to consider `Span` and `ReadOnlySpan` better than `string`, just as we did for array and interfaces implemented by arrays.  
We will support non-generic collection interfaces as target types, but possibly not until C# 13 in tandem with natural types for collection expressions.


