Question

So, given then following code

type MyClass () =
  let items = Dictionary<string,int>()
  do 
    items.Add ("one",1)
    items.Add ("two",2)
    items.Add ("three",3)
  member this.TryGetValue (key,value) =
    items.TrygetValue (key,value)
let c = MyClass () 

let d = Dictionary<string,int> ()
d.Add ("one",1)
d.Add ("two",2)
d.Add ("three",3)

And the following test code

let r1,v1 = d.TryGetValue "one"
let r2,v2 = c.TryGetValue "one"

The r1,v1 line works fine. The r2,v2 line bombs; complaining c.TryGetValue must be given a tuple. Interestingly, in each line the signature of TryGetValue is different. How can I get my custom implementation to exhibit the same behavior as the BCL version? Or, asked another way, since F# has (implicitly) the concept of tuple parameters, curried parameters, and BCL parameters, and I know how to distinguish between curried and tuple-style, how can I force the third style (a la BCL methods)?

Let me know if this is unclear.

Was it helpful?

Solution

TryGetValue has an out parameter, so you need to do the same in F# (via a byref marked with OutAttribute):

open System.Runtime.InteropServices 
type MyDict<'K,'V when 'K : equality>() =  // '
    let d = new System.Collections.Generic.Dictionary<'K,'V>()
    member this.TryGetValue(k : 'K, [<Out>] v: byref<'V>) =
        let ok, r = d.TryGetValue(k)
        if ok then
            v <- r
        ok            

let d = new MyDict<string,int>()
let ok, i = d.TryGetValue("hi")
let mutable j = 0
let ok2 = d.TryGetValue("hi", &j)

F# automagically lets you turn suffix out parameters into return values, so you just need to author a method that ends in an out parameter.

OTHER TIPS

Personally, I have never liked the bool TryXXX(stringToParseOrKeyToLookup, out parsedInputOrLookupValue_DefaultIfParseFailsOrLookupNotFound) pattern used throughout the BCL. And while the F# trick of returning a tuple is nice, rarely if ever do I actually need the default value if a parse or lookup fails. Indeed, the Some/None pattern would be perfect (like Seq.tryFind):

type MyClass () =
  let items = System.Collections.Generic.Dictionary<string,int>()
  do 
    items.Add ("one",1)
    items.Add ("two",2)
    items.Add ("three",3)
  member this.TryGetValue (key) =
    match items.TryGetValue(key) with
        | (true, v) -> Some(v)
        | _ -> None

let c = MyClass()

let printKeyValue key =
    match c.TryGetValue(key) with
    | Some(value) -> printfn "key=%s, value=%i" key value
    | None -> printfn "key=%s, value=None" key

//> printKeyValue "three";;
//key=three, value=3
//val it : unit = ()
//> printKeyValue "four";;
//key=four, value=None
//val it : unit = ()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top