Rainer Schuster
Rainer Schuster

Reputation: 112

F# Positional Arguments in Attributes

I'm trying to create an attribute in F# with positional arguments but failing all the time.

type ColumnAttribute(?index:int,?name:string) =
    inherit Attribute()
    let mutable index = index
    let mutable name = name
    member x.Index 
        with get() = index
        and set value = index <- value
        member x.Name 
        with get() = name
        and set value = name <- value

type Substance = {
    [<Column(Index=1)>] Name : string
    [<Column(Index=0)>] Id : int
    [<Column(Name="sequence")>] Sequence : string
}

I've tried several different approaches but this is the closest I ended with.

Upvotes: 2

Views: 691

Answers (4)

tranquillity
tranquillity

Reputation: 1685

I was able to get this working using the alternative syntax documented for optional arguments

type NamedAttribute([<Optional>] [<DefaultParameterValue("")>] name) = 
    inherit Attribute()
    new () = new NamedAttribute(?name = None)
    member val Name:string = name

module X = 
    [<Command(name = "")>]
    let f x = x

Upvotes: 0

Daniel
Daniel

Reputation: 47904

This works:

type ColumnAttribute() =
    inherit System.Attribute()
    let mutable index = 0
    let mutable name = ""
    member x.Index 
        with get() = index
        and set value = index <- value
    member x.Name 
        with get() = name
        and set value = name <- value

type Substance = {
    [<Column(Index=1)>] Name : string
    [<Column(Index=0)>] Id : int
    [<Column(Name="sequence")>] Sequence : string
}

Attributes already support property setter syntax similar to named arguments. To get what you want, use a parameterless constructor and rely on the attribute syntax, instead of named arguments (which don't work well with attributes anyway, because they're inferred as options...which don't qualify as constant expressions).

Upvotes: 2

JaredPar
JaredPar

Reputation: 754585

There are 2 issues that I see with your code

  1. In order for this to work you need to define a no-argument constructor for ColumnAttribute.
  2. The type of Index and Name is int option and string option respectively but you need it to be int and string.

Try the following

type ColumnAttribute(index:int option,name:string option) =     
    inherit Attribute()     
    let mutable index = index
    let mutable name = name
    new () = ColumnAttribute (None, None)
    member x.Index          
        with get() = match index with | Some i -> i | None -> 0
        and set value = index <- Some value         
    member x.Name          
        with get() = match name with | Some n -> n | None -> ""
        and set value = name <- Some value  

type Substance = {     
    [<Column(Index=1)>] Name : string     
    [<Column(Index=0)>] Id : int     
    [<Column(Name="sequence")>] Sequence : string }

Upvotes: 4

Brian
Brian

Reputation: 118865

Here you go:

open System

type ColumnAttribute() =
    inherit Attribute()
    let mutable index = 0
    let mutable name = ""
    member x.Index         
        with get() = index        
        and set value = index <- value        
    member x.Name         
        with get() = name        
        and set value = name <- value

type Substance = {    
    [<Column(Index=1)>] Name : string    
    [<Column(Index=0)>] Id : int    
    [<Column(Name="sequence")>] Sequence : string
}

Note that the optional parameters (e.g. ?index) in your original attempt were causing the types to be e.g. int option rather than int.

Upvotes: 0

Related Questions