2

Related to No argument names in abstract declaration?, how would you do this with a C#-style tupled argument? So if I wanted

abstract member createEmployee : (string * string) -> Employee

how would I be able to communicate whether it should be

1-   member this.createEmployee(firstName, lastName) = ...
2-   member this.createEmployee(lastName, firstName) = ...

Use case: creating an interface in F# to be used from C#.

Community
  • 1
  • 1
Dax Fohl
  • 10,654
  • 6
  • 46
  • 90

3 Answers3

7
abstract createEmployee: firstName:string * lastName:string -> Employee

compiles to create C# invocation semantics and the names appear both in C# and F# intellisense in Visual Studio 2013.

Dax Fohl
  • 10,654
  • 6
  • 46
  • 90
  • but this will give you no guarantees from the compiler that the user of your function does not mess up the order at all :) - but hey if it works for you ;) – Random Dev May 23 '15 at 11:20
  • @Carsten I see the advantage of your solution and would go with it if I were starting from scratch, but being in the middle of a big old project with compatibility concerns, this seems to be the pragmatic short-term solution. – Dax Fohl May 23 '15 at 11:42
  • hey no problem - whatever works (and as long as you have **FUN**) ;) – Random Dev May 23 '15 at 11:50
  • @Carsten Having *much* more fun now that I'm able to clear out the doSomething.Invoke(firstArg).Invoke(second).Invoke(third) etc from my c# code. Thanks for the pointer on not parenthesizing the args; the difference is very pronounced when calling from C#. – Dax Fohl May 23 '15 at 12:06
3

I think the easiest way is to go like this:

type FirstName = FirstName of string
type LastName  = LastName of string

...

abstract member createEmployee : (FirstName * LastName) -> Employee

remark:

you probably want it to be

abstract member createEmployee : FirstName * LastName -> Employee

instead as there are slight differences ;)

Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • Offhand, do you know if Json.net will serialize/deserialize those types as regular strings, or does it add extra stuff during serialization? Need to maintain api compatibility. – Dax Fohl May 23 '15 at 10:39
  • well no it will most likely have problems with that - I usually define DTOs if I have problem with this kind of stuff - sorry did not know you need it to work with serializers - want me to remove the answer? – Random Dev May 23 '15 at 10:40
  • So to extract the string would I have to do a `match` each time or is there a shortcut? – Dax Fohl May 23 '15 at 10:58
  • 3
    the usual shortcut is to deconstruct/pattern-match where you need it - for example `let myFun (FirstName fn) = ...` in F#, you don't really have to use `match` here as it's the only possibitie anyway - and you can add `member` function/properties to it as well if you like – Random Dev May 23 '15 at 11:00
3

There are two ways to do that:

  1. Use Named Arguments as described in MSDN

    member this.createEmployee(firstName: string, lastName: string) = ...
    
    // external code
    MyClass.createEmployee(firstName = "John", lastName = "Smith")
    MyClass.createEmployee(lastName = "Smith", firstName = "John")
    
  2. Make your class member accept a structure as an argument:

    type EmployeeName =
       struct 
          val firstName: string
          val lastName: string
       end 
    
    member this.createEmployee2(employeeName: EmployeeName) = ...
    
    // external code
    MyClass.createEmployee2 {firstName = "John"; lastName = "Smith"}
    MyClass.createEmployee2 {lastName = "Smith"; firstName = "John"}
    

The choice is yours; the former allows for optional arguments (consider middleName or salutation) while the latter allows for storing the structure together (e.g. if you need to process it further).

Be Brave Be Like Ukraine
  • 7,596
  • 3
  • 42
  • 66