BenchmarkDotNet icon indicating copy to clipboard operation
BenchmarkDotNet copied to clipboard

Support for F# anonymous records

Open psfinaki opened this issue 1 year ago • 3 comments

Repro

namespace Perf

open BenchmarkDotNet.Running
open BenchmarkDotNet.Attributes

module Main =

    type Test() =

        [<Benchmark>]
        member _.AnonymousRecord() =
            let array = Array.init 5 id
            array |> Array.countBy (fun n -> {| Field = n |})

    [<EntryPoint>]
    let main args = 
        printfn "Running benchmarks..."
        BenchmarkSwitcher.FromAssembly(typeof<Test>.Assembly).Run(args) |> ignore
        0

What happens

// Build Error: Standard output:

 Standard error:
 MSBuild version 17.10.0-preview-23619-02+5cf78584f for .NET
C:\Program Files\dotnet\sdk\9.0.100-alpha.1.23620.14\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(311,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,37): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,37): error CS1003: Syntax error, '(' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,80): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,94): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,94): error CS1003: Syntax error, ',' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,95): error CS1003: Syntax error, ',' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,96): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,114): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,114): error CS1003: Syntax error, ',' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,115): error CS8124: Tuple must contain at least two elements. [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,116): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(186,116): error CS1026: ) expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,38): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,38): error CS1003: Syntax error, '(' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,81): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,95): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,95): error CS1003: Syntax error, ',' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,96): error CS1003: Syntax error, ',' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,97): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,115): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,115): error CS1003: Syntax error, ',' expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,116): error CS8124: Tuple must contain at least two elements. [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,117): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(188,117): error CS1026: ) expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(239,29): error CS1519: Invalid token '<<' in class, record, struct, or interface member declaration [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(239,72): error CS1519: Invalid token ',' in class, record, struct, or interface member declaration [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(239,86): error CS1519: Invalid token '>' in class, record, struct, or interface member declaration [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(239,88): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(318,28): error CS1519: Invalid token '<<' in class, record, struct, or interface member declaration [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(318,71): error CS1519: Invalid token ',' in class, record, struct, or interface member declaration [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(318,85): error CS1519: Invalid token '>' in class, record, struct, or interface member declaration [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(318,87): error CS1001: Identifier expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(326,40): error CS1026: ) expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(326,42): error CS1525: Invalid expression term '>' [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(326,83): error CS1002: ; expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(326,83): error CS1513: } expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(326,100): error CS1002: ; expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]
FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\1a71ca95-94eb-441e-9549-46a619937196.notcs(326,100): error CS1513: } expected [FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196\BenchmarkDotNet.Autogenerated.csproj]

Build FAILED

    38 Error(s)
Time Elapsed 00:00:01.94

// BenchmarkDotNet has failed to build the auto-generated boilerplate code.
// It can be found in FSharpConsoleApp\bin\Release\net8.0\1a71ca95-94eb-441e-9549-46a619937196
// Please follow the troubleshooting guide: https://benchmarkdotnet.org/articles/guides/troubleshooting.html

What should happen

Well something more clear. It should either work or give a clear message. This might be related to the fact that anon records in F# are very generic under the hood and AFAIK BDN has problems with those.

Env

BenchmarkDotNet v0.13.12, Windows 11 (10.0.22621.3155/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK 9.0.100-alpha.1.23620.14
  [Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI DEBUG

psfinaki avatar Feb 26 '24 16:02 psfinaki

Please follow the troubleshooting guide: https://benchmarkdotnet.org/articles/guides/troubleshooting.html

BDN generates a C# project that references the F# project and generates a class that derives from the type that defined the benchmarks (to generate the boilerplate code and run every benchmark in a standalone process to avoid any side-effects affecting other benchmarks). Please use the link provided above and troubleshoot the issue (I suspect that BDN fails to reference the F# method with such name) and send a PR with a fix.

Here is the logic that generates the C# code: https://github.com/dotnet/BenchmarkDotNet/blob/master/src/BenchmarkDotNet/Code/CodeGenerator.cs

Here is the template it's filling: https://github.com/dotnet/BenchmarkDotNet/blob/master/src/BenchmarkDotNet/Templates/BenchmarkType.txt

adamsitnik avatar Feb 27 '24 06:02 adamsitnik

I'm guessing F# anonymous records are implemented similar to C# anonymous types where their underlying type name in IL cannot be expressed in C#. If that's the case, there is nothing we can do about it. You will have to wrap it in another type that C# can consume (or up-cast to object), or use an InProcess toolchain.

timcassell avatar Feb 27 '24 06:02 timcassell

I'm guessing F# anonymous records are implemented similar to C# anonymous types where their underlying type name in IL cannot be expressed in C#. If that's the case, there is nothing we can do about it. You will have to wrap it in another type that C# can consume (or up-cast to object), or use an InProcess toolchain.

Very well might be - in that case yeah, at least a proper error message would be helpful.

I haven't worked with debugging BDN yet but this looks like an interesting opportunity. Will post heads up here if I start working on this.

psfinaki avatar Feb 27 '24 12:02 psfinaki