# Collection literals working group meeting for April 4, 2023

## Agenda

* Allow efficient construction of collections that are typically represented as arrays, particularly `ImmutableArray<T>`.

## Discussion

We discussed possible _construction method_ patterns that would allow the compiler to write directly to the underlying storage for collections such as `ImmutableArray<T>` and `List<T>`, and avoid extra allocations or copying in cases where the collection has a _known length_.

There were two promising approaches that provide equivalent capability, with the difference of whether the underlying storage is allocated by the caller or by the collection.

### Pass ownership of array
One possible approach is a _construction method_ that takes an array as an argument and uses that array directly as the underlying storage of the collection, with the caller passing ownership of the array to the collection instance.

For instance, given the following method for creating an `ImmutableArray<T>`:
```csharp
// Create ImmutableArray<T> using the array as the underlying storage.
public static ImmutableArray<T> AsImmutableArray<T>(T[] array)
{
    // ...
}
```

The compiler could translate `ImmutableArray<T> result = [x, ..e, y];` to:
```csharp
T[] __array = new T[e.Count + 2];

int __i = 0;
__array[__i++] = x;
foreach (T __t in e)
    __array[__i++] = __t;
__array[__i++] = y;

ImmutableArray<T> result = AsImmutableArray(__array);
```

### Write directly to storage span
An alternative is a _construction method_ that creates a collection of a given size and returns the collection _and_ a span that refers to the underlying storage, and the caller populates the collection using the span.

For instance, given the following method for creating a `ImmutableArray<T>`:
```csharp
// Create ImmutableArray<T> and return a span to the underlying storage.
public static ImmutableArray<T> CreateImmutableArray<T>(int size, out Span<T> span)
{
    // ...
}
```

The compiler could translate `ImmutableArray<T> result = [x, ..e, y];` to:
```csharp
Span<T> __span;
ImmutableArray<T> result = CreateImmutableArray(e.Count + 2, out __span);

int __i = 0;
__span[__i++] = x;
foreach (T __t in e)
    __span[__i++] = __t;
__span[__i++] = y;
```

### Runtime libraries

The BCL could provide _construction methods_ for `ImmutableArray<T>` and `List<T>`, and perhaps a few additional collection types where the underlying storage can be represented as a span.

The methods could be implemented in `System.Runtime.InteropServices` or `System.Runtime.CompilerServices` to indicate the intended use is from compilers or interop.

### Compiler use
The compiler will use a _construction method_ for the corresponding collection type when creating a collection of _known length_.

When creating collections of _unknown length_, using a _construction method_ may not provide an advantage over existing alternatives since either approach may require resizing and reallocating during construction.

_What if the collection literal has a known length but the resulting collection instance is mutable? Is there an advantage to providing an initial length?_

_Construction methods_ could be registered with attributes on the _collection type_.

For instance, an attribute could identify the construction method by containing type and method name.
```csharp
[CollectionLiteralConstruction(typeof(ImmutableCollections), "AsImmutableArray")]
public struct ImmutableArray<T>
{
    // ...
}

public static class ImmutableCollections
{
    public static ImmutableArray<T> AsImmutableArray<T>(T[] array)
    {
        // ...
    }
}
```

A collection type should have at most one _construction method_. Most collection types will have none.
