F# Create custom attribute to expression
Asked Answered
P

1

12

In F#, how can I create a custom attribute to apply on expressions? I looked for resources everywhere, but I didn't find nothing.

For exemple The attribute [<Entrypoint>] can be applied to some expression, and by consequence the compiler can infer that expression should be of type array string -> int.

How can I create a custom attribute to work simillary ?

Prototherian answered 28/6, 2017 at 14:3 Comment(0)
L
19

To create a custom attribute, simply declare a class that inherits from System.Attribute:

type MyAttribute() = inherit System.Attribute()

[<My>]
let f x = x+1

As you can see, the suffix "Attribute" can be omitted when applying the attribute to code units. Optionally, you can give your attribute parameters or properties:

type MyAttribute( x: string ) =
    inherit System.Attribute()
    member val Y: int = 0 with get, set

[<My("abc", Y=42)>]
let f x = x+1

At runtime, you can inspect types, methods, and other code units to see which attributes are applied to them, and to retrieve their data:

[<My("abc", Y=42)>]
type SomeType = A of string

for a in typeof<SomeType>.GetCustomAttributes( typeof<MyAttribute>, true ) do 
    let my = a :?> MyAttribute
    printfn "My.Y=%d" my.Y

// Output:
> My.Y=42

Here is a tutorial explaining custom attributes in more detail.

However, you cannot use custom attributes to enforce compile-time behavior. The EntryPointAttribute is special - that is, the F# compiler knows about its existence and gives it special treatment. There are some other special attributes in F# - for example, NoComparisonAttribute, CompilationRepresentationAttribute, etc., - but you cannot tell the compiler to give special treatment to attributes that you yourself created.

If you describe your larger goal (i.e. what you're trying to achieve), I'm sure we'll be able to find a better solution.

Linnie answered 28/6, 2017 at 14:29 Comment(2)
I was wondering if it would be possible for the compiler to infer from the attributes, there was no larger goal. But I didn't know there were any special attributes, thanks!Prototherian
Is there a way in F# to do instead of typeof<SomeType> to do it over all types in a module? I want to capture all top-level lets I've annotated with some attribute, and if I missed one, fail a testBobbyebobbysocks

© 2022 - 2024 — McMap. All rights reserved.