Search code examples
f#overload-resolutionnamed-parameterspolly

How to use Named Arguments in F#


Calling a Dictionary's Add() method using named arguments works in F#.

let d = Dictionary<string, obj>()
d.Add(key = "five", value = 5)

let d2= Dictionary<obj, obj>()
d2.Add(key = "five", value = 5)
d2.Add(key = 5, value = 5)

In Polly's Context class , there is a similar Add() method with 2 overloads:

Add(key: obj, value: obj) : unit
Add(key: string, value: obj) : unit

And I can use it in all of these ways:

let c = Polly.Context()
c.Add("five", 5)
c.Add(5, 5)
c.Add(key = 5, value = 5)

But not this way, it says it can't resolve between the overloads and needs a type annotation.

c.Add(key = "five", value = 5)

Why is that and how can I fix it?


Solution

  • The compiler cannot work out which method to use. This is more common when dealing with C# and OO style in general with F#. I don't mind, keeps me functionally honest.

    The most straightforward way to fix your problem now would be to use:

    c.Add(key = ("five" :> obj), value = 5)

    By casting it there is no ambiguity about what the type is and the compiler is happy.

    Alternatively, you could create a function with explicit types and this will help the compiler figure it out as well. If you are using this a lot I suggest this:

    let addToPolly (ctx:Polly.Context) (k:obj) (v:obj) =
            ctx.Add(k,v)
            ignore()
    
    addToPolly c "five" 5
    

    UPDATE: As @brett pointed out I had inferred the answer but not been explicit. Here are some examples where the compiler is happy.

    let pollyAddAsString (ctx:Polly.Context) (k:string) (v:obj) = ctx.Add(key = k, value = v) |> ignore
    let pollyAddAsObj (ctx:Polly.Context) (k:obj) (v:obj) = ctx.Add(key = k, value = v) |> ignore
    pollyAddAsObj c "five" 5
    pollyAddAsString c "five" 5
    
    let (k:string,v:obj) = ("five", 5 :> obj)
    let (x:obj,y:obj) = ("five" :> obj, 5 :> obj)
    c.Add(key = k, value = v)
    c.Add(key = x, value = y)