Fsharp: Compiler generates instance method while creating Action from static member

Created on 20 Jan 2020  路  9Comments  路  Source: dotnet/fsharp

Consider following code:

open System
type C =
    static member M() = ()
    static member CreateAction() =
        new Action(C.M)

Compiler generates a closure object for C.M reference and changes static member in Action for instanced one. Please see decompiled C# code:

public static class _
{
    public class C
    {
        public static void M()
        {
        }

        public static Action CreateAction()
        {
            return new Action(new CreateAction@5().Invoke);
        }
    }

    internal sealed class CreateAction@5
    {
        internal void Invoke()
        {
        }
    }
}

While it doesn't capture anything generated code could use reference to static member itself. It is not clear if such behavior has any performance impact but it may affect use of .NET libraries.

E.g. ILGPU requires static methods for describing computational kernels and compiles it to GPU code via Action delegates. Please see example.

Area-Compiler bug

Most helpful comment

Thank you! It works fine.

All 9 comments

@dsyme any thoughts on this?

I'm sure this can be fixed.

@cartermp Could you please add labels to the issue? I'm afraid that it might get lost from sight. Thanks!

You betcha

@gsomix, @MoFtZ, your example is a void function returning void. Is the issue specific to that, or is it related to any number of arguments (but still returning void)?

And is the issue the same (does it also create an instance method reference as opposed to static) when creating a delegate type in F# from a void-returning function? It would be great if a fix covers both cases.

@abelbraaksma Yes, it's same.

open System

type MyAction2 = delegate of int -> unit
type MyAction3 = delegate of int * int -> unit

type C =
    static member M2(x: int) = Console.WriteLine(x)
    static member M3(x: int, y: int) = Console.WriteLine("{0} {1}", x, y)

    static member CreateAction2() =
        new Action<int>(C.M2)

    static member CreateAction3() =
        new Action<int, int>(fun x y -> C.M3(x, y))

    static member CreateMyAction2() =
        new MyAction2(C.M2)

    static member CreateMyAction3() =
        new MyAction3(fun x y -> C.M3(x, y))

Note also it's not possible to create multi-arguments delegate without involving lambda function.

Note also it's not possible to create multi-arguments delegate without involving lambda function.

Yea, that is kinda of unfortunate. You would think it could be tupled: (x, y) because of the signature int * int -> unit - I remember @KevinRansom and I looked at this before and it does feel a little confusing.

Thank you! It works fine.

Was this page helpful?
0 / 5 - 0 ratings