6

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?

Brett Rowberry
  • 1,030
  • 8
  • 21

1 Answers1

8

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)
Devon Burriss
  • 2,497
  • 1
  • 19
  • 21
  • This is a great answer for the obj, obj overload. How about the string,obj overload? – Brett Rowberry Jul 13 '18 at 04:32
  • 1
    Good point point @BrettRowberry. I have updated my answer. I hope this helps. Please let me know if not. – Devon Burriss Jul 13 '18 at 04:58
  • Is there a particular reason you NEED to use the named arguments? – Devon Burriss Jul 13 '18 at 04:59
  • This is great stuff. We can create helper functions as you did with pollyAddAsString/pollyAddAsObj or by creating and deconstructing tuples as you did with (k,v)/(x,y). – Brett Rowberry Jul 13 '18 at 14:49
  • F# is my favorite language. I never NEED to use named arguments in .NET, but I like them for resolving ambiguity. I first learned about 'named parameters' from Objective-C/Swift. When I learned they could optionally be included in .NET, I was very excited. The benefit of named parameters at the call site of a method is similar to the benefit records have over tuples. Records and tuples have pretty much the same capabilities, but the labels make it easier to read the code, especially when multiple parameters/arguments are distinguished by order because they have the same type. – Brett Rowberry Jul 13 '18 at 14:58