Tony
Tony

Reputation: 17647

How to do await an Async method, similar to C#

How to do an simple await in F# ?

In C# I have code like this:

await collection.InsertOneAsync(DO);
var r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO)

So I created a let await = ... to my F# code become more similar with my C# code.

My current F# code is this:

let awaits (t: Threading.Tasks.Task) = t |> Async.AwaitTask |> Async.RunSynchronously
let await (t: Threading.Tasks.Task<'T>) = t |> Async.AwaitTask |> Async.RunSynchronously


let Busca (numero) = 
    let c = collection.Find(fun d -> d.Numero=numero).ToList()
    c

let Insere(DO: DiarioOficial) =
    //collection.InsertOneAsync(DO) |> Async.AwaitTask |> Async.RunSynchronously
    collection.InsertOneAsync(DO) |> awaits

let Salva (DO: DiarioOficial) =
    //let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) |> Async.AwaitTask |> Async.RunSynchronously
    let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) |> await
    r

I want to have only one definition for await (awaits), but the best I could do is this, because on Insere, type is Task, but on Salva, type is Task<'T>

If i use only the await, I get this compile error:

FS0001 The type 'Threading.Tasks.Task' is not compatible with the type 'Threading.Tasks.Task<'a>'

If I use only the awaits, it compiles, but I lose the return type from the async Task
I want to merge the await and awaits in a single

let await = ...

How can I do this?

Upvotes: 2

Views: 793

Answers (2)

Tomas Petricek
Tomas Petricek

Reputation: 243051

There are two parts of writing async code in both F# and C#.

  • You need to mark the method or code block as asynchronous. In C#, this is done using the async keyword. The F# equivalent is to use the async { ... } block (which is an expression, but otherwise, it is similar).

  • Inside async method or async { .. } block, you can make non-blocking calls. In C#, this is done using await and in F# it is done using let!. Note that this is not just a function call - the compiler handles this in a special way.

F# also uses Async<T> type rather than Task<T>, but those are easy to convert - e.g. using Async.AwaitTask. So, you probably want something like this:

let myAsyncFunction () = async {
  let! _ = collection.InsertOneAsync(DO) |> Async.AwaitTask
  let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) 
  // More code goes here
}

I used let! to show the idea, but if you have an asynchronous operation that returns unit, you can also use do!

do! collection.InsertOneAsync(DO) |> Async.AwaitTask

Upvotes: 2

Roman Motyka
Roman Motyka

Reputation: 649

In F# we tend to use another syntax. It is described e.g. here: https://fsharpforfunandprofit.com/posts/concurrency-async-and-parallel/.

or here: https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async

The idea of working with C# Tasks is to "convert" them to async with Async.Await<'T>

You can do it probably another way, but it is the most straightforward.

Upvotes: 4

Related Questions