dotnet / dotnet/fsharp

Suboptimal code generated when pattern matching a tuple in a lambda parameter

Open
#16,037 0 comments 3 reactions 0 assignees View on GitHub
Area-Compiler-CodeGen Feature Improvement Theme-Performance
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 22h
Merged PRs (30d)
144

Description

When pattern matching a tuple in the parameter of a lambda function, the performance is inferior compared to using the `fst`/`snd` functions or pattern matching inside the function.

**Repro steps**

Consider the following example code:

```fsharp
let data = Map.ofList [
"1", (true, 1)
"2", (true, 2)
]

let foldWithPattern () =
(data, [])
||> Map.foldBack (fun _ (x, _) state -> x :: state)

let foldWithFst () =
(data, [])
||> Map.foldBack (fun _ v state -> fst v :: state)

let foldWithPattern2 () =
(data, [])
||> Map.foldBack (fun _ v state ->
let x, _ = v
x :: state)
```

I would expect the three functions to have similar performance and code-style-wise I would in many cases prefer the pattern match in the parameter.

[In the decomplied code](https://sharplab.io/#v2:DYLgZgzgPsCmAuACAJgQ3qxBeRBZVADgHQD2YAMgJYRIDaAsAFCIuIBEAjGwDSIAU8AE4BXWLw4BKJq3YAmHvyGjesqYwC6TJnCRgSwZAHVK8ABYAFdPFiCAdvwnZprPmgy9a6tTKhQAfHiERHoGAEKoAMYA1vxgwvYA+vwAHrwJjjTosIgAtAHJiCAgiJnWatoIiCFGJqYAYjQOTswubqgeXs4svgH4xNXh0bHxiEkAbiUY1rkBkEgTRZNZ3qwVuvo1Zpbw1nayTVhd/G0dK93+gf0bgzF8cYmIE6XZeUcyOoipo9iPb6wFi2eEiAA=), two FSharpFunc classes are created when the pattern matching in the parameter is used.

Benchmark result with the example code:

```
BenchmarkDotNet v0.13.8, Windows 10 (10.0.19045.3448/22H2/2022Update)
AMD Ryzen 7 1700, 1 CPU, 16 logical and 8 physical cores
.NET SDK 7.0.401
[Host] : .NET 7.0.11 (7.0.1123.42427), X64 RyuJIT AVX2 DEBUG
DefaultJob : .NET 7.0.11 (7.0.1123.42427), X64 RyuJIT AVX2

| Method | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio |
|---------------- |---------:|---------:|---------:|------:|-------:|----------:|------------:|
| FoldWithPattern | 58.40 ns | 1.113 ns | 1.041 ns | 1.00 | 0.0324 | 136 B | 1.00 |
| FoldWithFst | 39.90 ns | 0.483 ns | 0.452 ns | 0.68 | 0.0153 | 64 B | 0.47 |
```

**Expected behavior**

Pattern matching a tuple in a parameter does not affect performance.

**Actual behavior**

Pattern matching a tuple in a parameter degrades performance and causes more memory allocations.

**Known workarounds**

Use the `fst`/`snd` functions or do the pattern match in the body of the lambda function.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.