# Collection literals working group meeting for April 28, 2023

## Agenda

* Should a collection literal have a *natural type*? If so, what type?
* Infer the collection type from spread elements?
* Should dictionaries use overwrite or add semantics?

## Discussion

### Should a collection literal have a natural type? If so, what type?
[natural-type]: #natural-type

Without a *natural type*, a collection literal can only be used when *target typed* to a *constructible collection type*.

Given the *best common type* `T` of the elements, the choices for *natural type* include:
* `T[]`
* `List<T>`
* `Span<T>`
* `ReadOnlySpan<T>`
* `ImmutableArray<T>`

We ruled out `Span<T>` and `ReadOnlySpan<T>` because `ref struct` types cannot be used in `async` contexts.
Also, `ref struct` types cannot implement interfaces, so spans cannot be used as `IEnumerable<T>`.

Of the remaining types, `List<T>` is perhaps the most flexible and may satisfy more scenarios than `T[]` or `ImmutableArray<T>`.

Also, we speculate that `List<T>` is commonly used today in method bodies, so having `List<T>` as the *natural type* would be familiar and would align with existing code.

Another consideration is consistency between the *natural types* for non-dictionary and dictionary collection literals. The most obvious choice for dictionaries is `Dictionary<TKey, TValue>` which is consistent with `List<T>`.

However, different collection types are appropriate for different scenarios.

If `List<T>` is used as the *natural type* for a particular variable, but `Span<T>` or `T[]` could have been used explicitly instead, the choice of `List<T>` may be more expensive.

`List<T>` is mutable, even though it may be uncommon to mutate a collection that was created with an explicit initializer. That means consumers that want immutability will need to use an explicit type or wrap the instance.

The alternative is *no natural type*.

Collection literals are not a simple replacement for existing collection construction.
Previously, constructing and populating a collection required handling details of capacity, allocations, indexing vs `Add()` vs `AddRange()`, etc., and using `List<T>` may have been simpler or more familiar than alternative collection types.
Collection literals address that by providing a common syntax that can be used for a range of collection types.
Consumers can now choose the optimal collection type for each scenario, and requiring the developer to specify the collection type explicitly helps that.

Some other alternatives:
* Add support for *natural type* later.
* Support *natural type* behind a *feature flag*.
* Support *natural type* now and also include an analyzer that warns for `var` with collection literals for performance reasons.
* Support `var` element types, as suggested in a recent LDM: `List<var>`, `var[]`, `Dictionary<var, var>`, etc.

#### Conclusion
No conclusion, although the most likely options for *natural type* may be `List<T>` or *no natural type*.

### Infer the collection type from spread elements?
[infer-from-spread]: #infer-from-spread

Should the collection type of a collection literal be inferred from the collection types of any spread elements?
```csharp
ImmutableArray<int> a = [1, 2, 3];
var b = [..a, 4]; // ImmutableArray<int> b
```

What if spread elements have distinct types, such as `HashSet<object>` and `HashSet<string>`, or distinct comparers?

What if the spread element type is an interface, such as `IEnumerable<T>` or `IReadOnlyDictionary<TKey, TValue>`, or not a *constructible collection type*?

There is the potential for breaking changes to `var` collections when the types of spread elements change:
* between an interface and a concrete collection type, or
* between a constructible and non-constructible collection, by adding or removing a public constructor.

#### Conclusion
Requires further discussion.

### Should dictionaries use overwrite or add semantics?
[overwrite-or-add]: #overwrite-or-add

Should construction of a dictionary from a collection with duplicates use overwrite or add (and throw) semantics?

There are valid scenarios for both.
The concern is when combining collections where the collection types use distinct semantics.

There is a similar issue around comparers.
Consider the non-dictionary case when combining two `HashSet<T>` instances that use different comparers. There is potential for data loss in the resulting collection.

#### Conclusion
Requires further discussion.