Equivalent of C# async main in F# - f#

I was wondering what would be the equivalent of the C# async main in F#. More to the point, is there a special way of consuming/using async methods from main in an F# program or is it just a matter of waiting for completion?
To be more concrete, say we are using the .NET Core Generic Host.
In a C# program, main might look like this:
class Program
{
static async Task Main(string[] args)
{
await new HostBuilder().Build().RunAsync();
}
}
In an F# program, my instinct would be to do something like this:
[<EntryPoint>]
let main args =
HostBuilder().Build.RunAsync().Wait()
...or...
[<EntryPoint>]
let main args =
HostBuilder().Build.RunAsync() |> Async.AwaitTask |> Async.RunSynchronously
...or...
[<EntryPoint>]
let main args =
async {
return HostBuilder().Build.RunAsync() |> Async.AwaitTask
} |> Async.RunSynchronously
...or just avoid async...but that's no fun...
[<EntryPoint>]
let main args =
HostBuilder().Build.Run()
There are a few more formulations I could show but I think these make the point.
I imagine that part of the answer lies in answering these other questions
"what does it mean to run an async main method" and
"what's the point of making main async?"
Going by examples, async main seems mostly to be about making it possible for other places to call main in an async way (in those cases where main is not really "main", ie. unit testing, etc).
In the case of F#, I imagine there are at least 2 things preventing one from just returning an Async computation from main:
The EntryPointAttribute that enforces an int return type for status codes...right?
The compiler probably is not prepared to handle the async computation as the exit value of the program...right?

AFAIK there's no async main equivalent in F#.
If you look at C# implementation behind the scenes it looks like this:
private static void <Main>(string[] args)
{
Program.Main(args).GetAwaiter().GetResult();
}
Program.Main is the async main.
Personally I find this pattern slightly scary depending on what SynchronizationContext is used.
To emulate async main I would:
let theAsyncTask : Async<int> = ...
[<EntryPoint>]
let main argv =
async {
do! Async.SwitchToThreadPool ()
return! theAsyncTask
} |> Async.RunSynchronously
theAsyncTask is the actual work to be done, the embedded async switches to the thread pool so that the main thread can safely block and await the result.

Related

F# Async completion source?

I want an async to wait for a value to be provided. C# has a mechanism for doing this in tasks, but I am using async.
Here is what I came up with:
type AsyncCompletionSource<'t>() =
let tcs = TaskCompletionSource<'t>()
with
member this.Set(x : 't) =
tcs.SetResult(x)
member this.Get
with get () =
Async.AwaitTask tcs.Task
I was wondering if there is something already provided for this in F#?
And if not, is there a way to accomplish this without jumping in and out of task?
Also called: future, promise, settable future, subject

How to start multiple windows from F# using Elmish.WPF?

I am a newbie to Elmish.WPF and F#. In studying the tutorial on NewWindow/NewWindow.Views, the authors have assigned the following code from C# :
using System;
using Elmish.WPF.Samples.NewWindow;
using static Elmish.WPF.Samples.NewWindow.Program;
namespace NewWindow.Views {
public static class Program {
[STAThread]
public static void Main() =>
main(new MainWindow(), () => new Window1(), () => new Window2());
}
}
That is calling the main method in the F# NewWindow.Views project:
let main mainWindow (createWindow1: Func<#Window>) (createWindow2: Func<#Window>) =
let createWindow1 () = createWindow1.Invoke()
let createWindow2 () =
let window = createWindow2.Invoke()
window.Owner <- mainWindow
window
let bindings = App.mainBindings createWindow1 createWindow2
Program.mkSimpleWpf App.init App.update bindings
|> Program.withConsoleTrace
|> Program.runWindowWithConfig
{ ElmConfig.Default with LogConsole = true; Measure = true }
mainWindow
How can the F# module main routine be changed so as to use it directly as the EntryPoint and avoid it being a function? That is, I would like the F# module to have direct control over the windows via Elmish. Something along the lines as below but with the invocation of the subordinate windows self-contained:
/// This is the application's entry point. It hands things off to Elmish.WPF
[<EntryPoint; STAThread>]
let main _ =
Program.mkSimpleWpf init update bindings
|> Program.runWindow (MainWindow())
In short, I would like the C# Views to have no knowledge of the F# project.
Can this be done with Elmish.wpf?
Any help (especially sample code :) ) would be most helpful.
I am one of the maintainers of Elmish.WPF. Until very recently, all the samples used their F# project as the entry point. If you clone the repo and check out this commit, then you can inspect those samples and see how to achieve your goal.
Going forward, I created this issue to consider including at least one sample with an F# project as its entry point.
In the future, feel free to ask any of your Elmish.WPF questions by opening an issue in our GitHub.

What is 'task' in F#?

let CreateEventSourcingConnection() =
task {
let connection =
let ipEndPoint = IPEndPoint(IPAddress.Loopback, 1113)
EventStoreConnection.Create(ipEndlPoint)
do! connection.ConnectAsync()
return connection
}
For task I get:
The value of constructor 'task' is not defined.
So, what is this and how can I define it?
I assume that the question is in the context of Logary, which gets the task computation builder from the TaskBuilder.fs NuGet package (as we can see from Paket references). The TaskBuilder.fs project is available here with some documentation.
So, task is a variable that represents an instance of the TaskBuilder computation builder. This is an F# computation expression, which lets you create computations that create the .NET Task<T> type as the result. Inside the computation expression, you can use let! and do! for the same purpose as await in C#, that is for waiting until some asynchronous operation completes (without blocking a thread):
task {
do! Console.Out.WriteLineAsync("Enter a filename:")
let! name = Console.In.ReadLineAsync()
use file = File.CreateText(name)
for i in Enumerable.Range(0, 100) do
do! file.WriteLineAsync(String.Format("hello {0}", i))
do! Console.Out.WriteLineAsync("Done")
return name
}
Here, WriteLineAsync and ReadLineAsync are .NET methods that return Task and we can use them as if they were returning just string or unit.
It is also worth adding that Logary is perhaps not the easiest piece of F# code to look into. It is very clever and nice, but relies on the HOPAC concurrency library which requires a fair bit of background knowledge and uses a number of fancy operators, which can make code quite tricky to understand. So if you are relatively new to F#, understanding HOPAC code might be a bit of a struggle!

Always use threadpool threads for continuations in async

Is there a way to instruct F# to always use threadpool threads for continuations in async computation expressions regardless of the synchronization context?
Sure you use Async.SwitchToThreadPool or another Switch... method
like this:
async {
do! Async.SwitchToThreadPool ()
// ... your other stuff
}

How to await TaskAwaiter or ConfiguredTaskAwaitable in F#

In C# awaiting the task awaiter is or ConfiguredTaskAwaitable is quite easy - just use await. What is the alternative for F#?
let! result = ...? doSomething().ConfigureAwait(false) ...?
F# async workflows and C# async-await keywords are two entirely separate mechanisms, and as such they are not directly compatible (though no doubt you can have wrappers that make that possible and most likely there are already wrappers like this around).
If you want to combine tasks with F# async workflow, you'd use the actual tasks rather than awaiters:
let! result = Async.AwaitTask task
If you have an API that gives you awaiters rather than tasks, here's a heavy-handed attempt at making an async out of a TaskAwaiter<'T>:
module Async =
let fromTaskAwaiter (awaiter: TaskAwaiter<'a>) =
async {
use handle = new SemaphoreSlim(0)
awaiter.OnCompleted(fun () -> ignore (handle.Release()))
let! _ = handle.AvailableWaitHandle |> Async.AwaitWaitHandle
return awaiter.GetResult()
}

Resources