fsharp / fsharp/fslang-suggestions

Type-directed resolution of [ .. ] syntax

Open
#1,086 43 comments 56 reactions 0 assignees View on GitHub
area: lists-arrays-sequences
Dominant language
No language data
Stars
373
Forks
21
PR merge metrics
No merged PRs in 30d

Description

I propose we consider doing type-directed resolution of the `[...]` syntax if used with a non-list known type.

```fsharp
type SomeApi() =
static member SomeEntryPoint(xs: ImmutableArray<_>) = ...

SomeApi.SomeEntryPoint([1; 2; 3])
```

The main thing here is that whenever a method needs a collection (of more or less any kind), as input, you can always use, for example, `[1;2;3]` and not think about it.

This means F# APIs can reasonable choose to adopt ImmutableArray or other such collection types for inputs without particularly changing user code.

If this is considered reasonable, the question arises about when this is allowed. For example, it's possible that it should just be at method argument position - F# has a tradition of only applying such "magic" (e.g. lambda --> delegate, `ParamArray` and more recently `op_Implicit`) only at method applications. However in theory it could also be at any position by type-directed resolution, e.g.
```fsharp
let x: ImmutableArray<_> = [1;2;3]
```

For some reason people don't seem to mind these transformations at method calls.

From a previous suggestion:

> Have the [ ... ] syntax resolved in a type-directed way (e.g. "if the target type is known to be a collection C with a builder pattern or IEnumerable constructor, then treat the syntax as if it is constructing a C, otherwise treat it as a regular F# list"))?

The syntax would work with

* list types
* array types by obvious translation
* Set/Map types (we would add a builder for these)
* ReadOnlySpan or Span, using stackalloc.
* Mutable collection types that have a constructor (optionally with a capacity arg), and an 'Add' method to add the elements.
* System.Collections.Immutable through a builder pattern definable via extensions or naming

This is somewhat related to the ListCollector type in F# 6 which is use as our builder for F# immutable lists and which gave the performance results described here. The only subtlety there is the presence of AddManyAndClose that allows lists to be collected in tail position without copying the list.

The underlying problem here is that we over-emphasise the "list" type in F# - that is, in an API designer wants to get nice, minimal callside syntax, they have no choice but to accept F# lists. However this has problems
* It can be relatively highly allocating
* It's not pleasant from C#
* It's probably not the data representation used inside the API. For example [the F# quotations API](https://fsharp.github.io/fsharp-core-docs/reference/fsharp-quotations-fsharpexpr.html#Applications) uses `list` throughout. but internally converts to arrays.

## Pros and Cons

The advantages of making this adjustment to F# are:
* nice syntax for many more collection types.

The disadvantages of making this adjustment to F# are:
* performance can vary significantly based on type annotation
* harder to work out what actual objects are being allocated
* you need a type annotation or strongly known type
* there are two ways to do arrays, i.e. `[| 1;2 |]` and via known type `([ 1; 2 ]: int array)`

## Extra information

Estimated cost (XS, S, M, L, XL, XXL): M

Related suggestions: (put links to related suggestions here)

## Affidavit (please submit!)

Please tick this by placing a cross in the box:
* [x] This is not a question (e.g. like one you might ask on [stackoverflow](http://stackoverflow.com)) and I have searched stackoverflow for discussions of this issue
* [x] I have [searched both open and closed suggestions on this site](http://github.com/fsharp/fslang-suggestions/issues) and believe this is not a duplicate
* [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:
* [x] This is not a breaking change to the F# language design
* [x] I or my company would be willing to help implement and/or test this

## For Readers

If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.

Contributor guide

No contributing guide indexed for this repository

Research direction

The proposal does not name implementation files, tests, or entry points. Start by reviewing how F# currently resolves list, array, ParamArray, op_Implicit, and ListCollector syntax, then establish the allowed type-directed cases and their semantics; done requires an agreed language design and implementation or testing plan.

Written by the indexing model from the issue text.

Assessment

Tech stack
fsharp
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.