Collection literals working group notes 2023-05-10 (#7190)
* Collection literals working group notes 2023-05-10 * Fix .md syntax highlighting Co-authored-by: Rikki Gibson <rikkigibson@gmail.com> --------- Co-authored-by: Rikki Gibson <rikkigibson@gmail.com>
This commit is contained in:
Родитель
5ef1e8d29d
Коммит
efda7a2ab5
|
@ -0,0 +1,86 @@
|
|||
# Collection literals working group meeting for May 10, 2023
|
||||
|
||||
## Agenda
|
||||
|
||||
* Discuss new options for natural typing of collection literals
|
||||
|
||||
## Discussion
|
||||
|
||||
Coming out of the previous full LDM on collection literals ([notes](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md#collection-literal-natural-type)), we wanted to explore more options for attaining both flexible usage and ideal performance with a natural type. Two alternatives were presented which had been fleshed out with potential designs.
|
||||
|
||||
### Option 1: anonymous/unspeakable 'collection builder' type
|
||||
|
||||
This approach gives the natural type _builder_ semantics with a set of APIs such as `Add` and `AddRange`:
|
||||
|
||||
```cs
|
||||
var collection = [1, 2, 3];
|
||||
collection.Remove(2);
|
||||
TakesImmutableArray(collection);
|
||||
```
|
||||
|
||||
The natural type would be anonymous. The compiler would realize the collection by directly initializing an `ImmutableArray<T>` in the example above, skipping any intermediate bookkeeping that is statically possible to skip, so that the best performance is achieved.
|
||||
|
||||
The extra builder concept changes how users would think about naturally-typed collection literals. This could make the mental model more complex. An explicit 'build' called out somehow in syntax might even be preferable over passing the variable implicitly as the targeted collection type.
|
||||
|
||||
We briefly considered whether there would be merits to making the type speakable, a new framework collection builder type that could be passed around. It would be yet another collection/builder type to teach people about. If the new builder type was itself capable of doing the building on the stack, it wouldn't be able to be captured or used across awaits. It would also be an advanced type which we wouldn't want normal users to be working with every time they use a naturally-typed collection literals.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
The working group had some hesitations with this approach.
|
||||
|
||||
### Option 2: optimize away `List<T>`
|
||||
|
||||
Under this option, the natural type of collection literals would be `List<T>` as previously proposed. A `List<T>` instance would not actually be created if a different backing storage performs better and the difference is not observable by the code.
|
||||
|
||||
These performance benefits would extend to all existing code that creates a new `List<T>` instance using syntax. No `List<T>` would be created in code such as the following; instead, this would be lowered to `stackalloc` or similar:
|
||||
|
||||
```cs
|
||||
List<int> list = new List<int> { 1, 2 };
|
||||
foreach (var item in list) // Only usage of 'list'
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
Tuples are one example of prior art, where the compiler assumes implementations of System.ValueTuple to be well-behaved and skips creating them altogether in some cases when tuple syntax is used.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
The working group was interested in pursuing this approach.
|
||||
|
||||
One hesitation is that it might be hard to reason about when the optimizations are happening, and when you're actually getting a `List<T>` at runtime. Are hidden diagnostics and analyzers enough? We will think about this further.
|
||||
|
||||
### Forward inference of the element type
|
||||
|
||||
We considered whether it would be advantageous to match the builder pattern seen in other languages without explicitly typing the collection variable:
|
||||
|
||||
```cs
|
||||
// Infers the element type to be 'int' by looking forward
|
||||
// to the Add call.
|
||||
var collection = [];
|
||||
collection.Add(1);
|
||||
```
|
||||
|
||||
Building a collection by starting without items is common, and this would enable users to use `var` instead of `List<int>` or creating some other builder.
|
||||
|
||||
Choosing the element type by examining calls and usages of the collection itself could result in errors which are hard for users to figure out. It would be similar to lambda return type inference. Lambda return type inference usually works well, but inference errors while editing are sometimes create really confusing diagnostics far away. Would we be making this poor kind of experience more common?
|
||||
|
||||
#### Conclusion
|
||||
|
||||
The working group was reluctant to embrace forward inference of element types unless forward inference became available for variables in a more general way, either by inferring generic type arguments as in `Service<_> s = ...` or even embracing forward inference completely by allowing `var s;`.
|
||||
|
||||
### Conversions from `List<T>` to other collections
|
||||
|
||||
One of the things that the builder option would have done is allow naturally-typed collections to be passed as a specific collection type later. If we go with option 2 instead, would we want to retain this ability by allowing `List<T>` to implicitly or maybe explicitly convert to any other collection type?
|
||||
|
||||
```cs
|
||||
var collection = [1, 2];
|
||||
TakesImmutableArray(collection); // Or Span
|
||||
```
|
||||
|
||||
#### Conclusion
|
||||
|
||||
The working group leaned toward doing nothing special for implicit or explicit conversions from `List<T>`, and having the above code fail to compile.
|
||||
|
||||
### Next steps
|
||||
|
||||
We will delve into option 2.
|
Загрузка…
Ссылка в новой задаче