F# - Using Concurrent.ConcurrentDictionary.TryRemove with dotnet 5

Viewed 295

I'm migrating my F# code from dotnet3.1 to 5 and struggling with following code:

        let tryRemove key (dict: Concurrent.ConcurrentDictionary<'a, 'b>) =
           match dict.TryRemove(key) with
           | (true, v) -> Some v
           | (false, _) -> None

In 3.1 TryRemove returned tuple, in version 5 it returnes only boolean value. To get value from dictionary I need to pass reference as second parameter of TryRemove. What is the correct way to do it and avoid returning null v?

I have tried following code:

    let tryRemove key (dict: Concurrent.ConcurrentDictionary<'a, 'b>): 'b option =
       let mutable v: 'b = null
       match dict.TryRemove(key, &v) with
       | true -> Some v
       | _ -> None

But now function that uses it thinks that it is possible to have null inside that Option from tryRemove

error FS0001: The type '(Body -> unit)' does not have 'null' as a proper value

where b' is (Body -> unit)

2 Answers

The problem is that .NET 5 added an overload. Before there was only TryRemove (key : 'a, byref<'b> value) : bool, now the new overload TryRemove(item: KeyValuePair<'a, 'b>) : bool gets chosen. See netcore 3.1 vs NET 5

An alternative solution is to add a type annotation, e.g.

let tryRemove (key: 'a) (dict: Concurrent.ConcurrentDictionary<'a, 'b>) =
   match dict.TryRemove(key) with
   | (true, v) -> Some v
   | (false, _) -> None

I have just figured out the:

let mutable v = Unchecked.defaultof<'b>

instead of

let mutable v: 'b = null

works, but it's super strange the simplified syntax with last out argument translated to tuple result does not work anymore. Does it?

EDIT
It still works! See the right answer :)

Related