fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

Bubble-up function attributes to `FSharpFunc<_,_>` so they can be used more easily

Open 64J0 opened this issue 1 year ago • 3 comments

Is your feature request related to a problem? Please describe.

Hello, hope you're good. I'm taking a look at the available approaches for reading custom attributes from a function definition and eventually found this page from StackOverflow: https://stackoverflow.com/a/65157463/10146684.

The way of doing this, according to this answer from SO, demands the knowledge of the module that the function is defined, which does not really fit my needs.

Then, I thought that it could be more practical if the attributes defined for a specific function were "bubbled-up" to the FSharpFunc<_,_> instance, so we can directly retrieve those attributes from it.

Disclaimer: I don't know the real impact of this change, but at least in theory I think it makes sense.

Describe the solution you'd like

Replicate the function attributes at the FSharpFunc<_,_> instance to make it easier to retrieve this information for functions, using something like:

type MyAttribute(value: int) =
    inherit System.Attribute()
    member this.Value = value

[<My(42)>]
let myFunction() = ()

myFunction.GetType().GetCustomAttributes(true)

Describe alternatives you've considered

Additional context

64J0 avatar Oct 08 '24 17:10 64J0

Techinally a function in a module is a static method in a static class while fsharpfunc is a dedicated type.

This can create friction as there ateibutes that have strict attribute usage e.g. method or class etc.

You could bubble up some attributes to a synthesized type but not all of them due to these constraints.

I don't think it's a good idea tbh.

I believe there were proposals along of methodinfoof(...) in C# to simplify scenarios like these but they never got real traction.

En3Tho avatar Oct 08 '24 17:10 En3Tho

F#9 did have big improvements in attribute targets, which would fail with this - I guess the expectation is to annotate the function like a method, but the runtime representation of the FsharpFunc is a class.

T-Gro avatar Oct 14 '24 16:10 T-Gro

Yeah, we might need to think where to emit them - on type, on Invoke method, on method which has the same name as function? In all of those cases - do we "special-case" the attribute targets and widen them to be allowed on more targets than it (possibly) initially is? Also, a separate discussion is what do we do on anonymous funcions? Right now attributes aren't propagated anywhere from them, and I think it was strictly rejected as suggestion.

vzarytovskii avatar Oct 14 '24 16:10 vzarytovskii

I think the goal of this would be to read the attributes of the method at the delegate target. I suppose the C# delegate equivalent of this would be .. GetMethodImpl or the Method property on delegate.

https://learn.microsoft.com/en-us/dotnet/api/system.delegate.getmethodimpl?view=net-8.0 https://learn.microsoft.com/en-us/dotnet/api/system.delegate.method?view=net-8.0

We could certainly implement something similar on the various FSharpFunc types and add the codegeneration to provide an override that gets the methodimpl for the necessary function. However, this means that every function value would cause us to generate an additional func, so we would probably want to measure the impact and make it opt-in.

An alternative would be as Vlad suggested, codegen the attributes on the generated Invoke method, which would also increase the size of the built assembly because the attributes would be duplicated, but only in the case of methods with custom attributes, which is likely better.

All in all I think I prefer attributing the invoke, but Method/GetMethodImpl would be a bit more reflection friendly.

KevinRansom avatar Nov 11 '24 19:11 KevinRansom