# Params Improvements Working Group Meeting for October 25, 2022
This was the first meeting of the _`params` improvements_ working group.
We discussed extending `params` support to collection types other than arrays.

## Agenda
1. `params IEnumerable<T>`, `IList<T>`, etc.
1. `params List<T>`, `ImmutableArray<T>`, etc.
1. `params Span<T>`, `ReadOnlySpan<T>`
1. Overload resolution and backward compatibility

## Discussion

### Interfaces and collection types: `params IEnumerable<T>`, `List<T>`, etc.

Perhaps the most common request is support for `params IEnumerable<T>`. 

This is potentially useful for scenarios where the `params` method simply iterates over the collection, and where callers might have an `IEnumerable<T>` instance rather than a `T[]` and are calling the method with _normal form_.
However, when callers use _expanded form_, a `params IEnumerable<T>` may not provide any advantage over `params T[]` to the caller or callee.

If we extend `params` to support `IEnumerable<T>`, we should consider extending `params` support to other interface types and concrete collection types as well.
If so, what are the requirements of supported types?

The [_collection literals working group_](https://github.com/dotnet/csharplang/tree/main/meetings/working-groups/collection-literals) is already defining similar requirements for _constructible collection types_. Those types can be `interface` types or concrete `class`, `struct`, and `ref struct` types.
The _collection literals_ proposal specifies how the corresponding collection instances for _constructible collection types_ are constructed and populated.

Any additional `params` types should match the _collection literals_ approach.
That is, for any particular `params` type, the code generated for `WriteLine(fmt, a, b, c)` should be equivalent to the code generated for `WriteLine(fmt, [a, b, c])`.

That said, the difference between an _expanded form_ call (with implicit collection) and a call using a _collection literal_ is just two characters, `[]`, so the advantage of `params` over _collection literals_ seems small.
Given that, we concluded we _should not extend `params`_ to arbitrary interfaces or collection types.

### Spans: `params ReadOnlySpan<T>`, `Span<T>`

`ReadOnlySpan<T>` has a couple of advantages over other potential `params` types.
1. With runtime support, the compiler could create spans at call sites without allocating an underlying array on the heap.
1. `T[]` and `Span<T>` are implicitly convertible to `ReadOnlySpan<T>`.

That means `params ReadOnlySpan<T>` is a reasonable alternative to `params T[]` in new APIs.
And for existing APIs, adding a `params ReadOnlySpan<T>` overload could reduce allocations for current callers of a `params T[]` overload without changing the calling code.

The potential perf benefit, and the opportunity to replace `params T[]` with `params ReadOnlySpan<T>` seem sufficiently important that we should support `params ReadOnlySpan<T>` even if _collection literals_ provide similar optimizations for span literals - that is, even if the difference between using `params` and using a _collection literal_ is simply `[]`.

`Span<T>` has the same benefits as `ReadOnlySpan<T>`, but `Span<T>` is only preferable to `ReadOnlySpan<T>` if the `params` method modifies the span.
But modifying a `params` span is not a pattern we should encourage - in part because modifications are not visible to callers where the compiler generated the `Span<T>` instance.
In short, we concluded we should support `params ReadOnlySpan<T>` but not `params Span<T>`.

`params ReadOnlySpan<T>` should be implicitly `scoped` so the compiler can reuse the implicitly generated `ReadOnlySpan<T>` instance across multiple calls in the calling method.

Should we also support `params scoped T[]`, to allowing sharing the array across callers?

### Overload resolution and backward compatibility

Overload resolution should prefer an overload with `params ReadOnlySpan<T>` over an overload with `params T[]`, to ensure call sites get benefit from reduced allocations.

That means adding a `params ReadOnlySpan<T>` overload to an API with a `params T[]` overload is a source breaking change.

### Conclusions
Extend `params` support to `ReadOnlySpan<T>` only.

`params ReadOnlySpan<T>` parameters should be implicitly `scoped`.

Overload resolution should prefer `params ReadOnlySpan<T>` over `params T[]`.

Consider support for `params scoped T[]` as an open question.
