This is the second meeting of the collection literals working group. The proposal is currently located at #5354.
List<>
/Dictionary<,>
/KeyValuePair<,>
being first-class concepts- Use of
Enumerable.TryGetNonEnumeratedCount
- Known-length and unknown-length spreads not affecting what the user sees
- Calling
.Count
along with each spread element evaluation or in a later phase k: v
dictionary element equivalent to KeyValuePair expression element- Natural typing with empty literals
- Unsupported cases
- Allowing target-typing to interfaces
- Implementation strategy for dictionary spreads
- Type parameters of the natural type for dictionary literals
Positive reception for tying k: v
syntax to KeyValuePair and allowing dictionary elements alongside expression elements. If there's a typo and a colon is accidentally added or removed, we think the compiler can create a helpful diagnostic.
What should we do if someone tries to use dictionary elements to call collection indexers?
List<string> list = [0: "first", 1: "second"];
We could identify if the indexer being called is mapped to a list interface indexer and not a dictionary interface indexer. We should think about this more because we'd want to consider graph-like collections.
To determine the type parameters for the Dictionary<,>
natural type, we definitely need both expressions (from the dictionary elements) and types (from the expression elements and spread elements) as inputs to the best common type algorithm.
We want [..dict1, ..dict2]
to produce a dictionary, so the target type will be a dictionary when the expression elements and spread elements bring in only KeyValuePair instances even if there is no dictionary element k: v
.
We agreed that there should be no natural type for [k: v, someObject]
. If there is a dictionary element and don't get a dictionary, that's very confusing. If you want a list, you can explicitly type as List<object>
which will then contain the KeyValuePair created by k: v
.
We like using Enumerable.TryGetNonEnumeratedCount
in the codegen when available. We aren't sure where to draw the line in specifying improvements like this in the spec instead of leaving it up to the compiler, which the spec already invites to take initiative in improving codegen for runtime performance.
We think it will be imperative for span users that codegen uses stackalloc when target-typing Span<T>
. Is it acceptable for there to be resizes (TryGetNonEnumeratedCount
returns false)? We want input from experts in these areas about how to make good use of stack and heap memory for these use cases, and whether to allow spreads of known or unknown length when target-typing to spans. If we disallow spreads when target-typing to spans, users can create an array using (T[])[...]
to obtain a heap-allocated span.
Positive reception for the general concept that users won't get errors that force them to understand known-length versus unknown-length spreads when the target type is fixed-length and doesn't have a Construct
method. We can always generate code to make this work.
Hesitation around not being visible enough when unknown-length spreads are resulting in resize reallocations. However, analyzers can show when this happens, either any spread or ones that don't have a known length. It feels important to be able to spread unknown-length enumerables into arrays or immutable collections. Roslyn code does this commonly and it would be unfortunate not to be able to use collection literals for this.
Collection literals should be thing that gets you the best performance rather than everyone figuring it out by hand. Roslyn wouldn't want to give up its ArrayBuilder helper, but maybe the compiler can implement private pools in its codegen for collection literals. This would require a robust codegen strategy, but but we like that. The codegen strategy could improve over time. The yearly .NET performance blog post could say, "Are you using collection literals? Now your code is faster!"
We don't want users to be surprised at later spread elements having been evaluated if calling .Count
on an earlier spread element throws an exception. However, this is necessarily the case anyway if an exception is thrown during enumeration. We decided to table this for now.
[]
should have a special type, similar to how the null literal has a null type, which allows it to participate in things such as conditional expressions or lists of lists. We'll work on speccing this. We'd like to see if we can make var list = cond ? [str] : [obj];
work too.
Let's reoutline the spec so nuggets of reasoning aren't buried. We want to invest in realistic examples before presenting at the LDM too.
The next meeting is currently planned for October 21st, 2022. We will discuss remaining unresolved questions from the spec:
- Immediate indexing into a collection literal
- Use of AddRange or CopyTo when available
- Use of
Add(KeyValuePair<K, V>)
when the collection is a dictionary - Allowing spreads when target-typing to spans and which kinds (requiring intermediate resizes or not)
- Stackalloc and spans