Let's consider the following code:
type RulesStore() =
...
static member LoadAsync : Async<RulesStore> =
async {
let! r = Startup.States.GetAsStringAsync("rules") |> Async.AwaitTask
return
if String.IsNullOrEmpty r then
new RulesStore()
else
JsonConvert.DeserializeObject<RulesStore>(r);
}
This is a static method inside an object and is used to get an instance of that object, either from a stored json, or a new clean one.
Am I right to believe that if I replace:
static member LoadAsync : Async =
with
let LoadAsync : Async =
LoadAsync would be evaluated once and subsequent loads would return the same result? if I am wrong, why is this?
This is a bit more subtle. First, you are comparing let (instance) with static member (static), which adds the obvious difference between things that happen for each instance and things that are shared by all instances.
A more useful comparison is to compare regular member and let. The subtle thing is that async computations are themselves delayed, so they only run body when you execute them.
The following is a sample to illustrate this - I added one printf before the definition of async and one inside the async block, for both let and member:
type A() =
let test =
printfn "let: before async"
async {
printfn "let: inside async"
}
member x.Test =
printfn "member: before async"
async {
printfn "member: inside async"
}
member x.RunLet() = test |> Async.RunSynchronously
member x.RunMember() = x.Test |> Async.RunSynchronously
Here is what the code does:
let a = A()
// prints "let: before async"
a.RunLet()
// prints "let: inside async"
a.RunLet()
// prints "let: inside async"
a.RunMember()
// prints "member: before async"
// and "member: inside async"
a.RunMember()
// prints "member: before async"
// and "member: inside async"
As you can see, the code "inside async" runs repeatedly each time you invoke the async computation. However, the code "before async" runs only once for let and repeatedly for member.
In reality, you almost never have code before async, so this does not make much difference in typical uses, but there is some difference - with let, the async computation is constructed just once and then reused each time.
Related
Here is a client side Fable.Remoting example that prints the result of an async function.
// Client code (Compiled to Javascript using Fable)
// ============
open Fable.Remoting.Client
let server = Proxy.create<IServer>
async {
let! length = server.getLength “hello”
do printfn “%d” length // 5
}
|> Async.StartImmediate
How do I get the length value?
I see you've tagged your question with elmish, so I'm going to assume you have a Msg type defined. Don't use Async.StartImmediate or Async.RunSynchronously; in Elmish, you should use Cmd.OfAsync to schedule a message to be dispatched once the async block returns a value. There are four functions in Cmd.OfAsync (and the same four appear in Cmd.OfPromise as well): either, perform, attempt, and result. I'll break them down for you since their documentation isn't quite up to snuff yet:
either: takes four parameters, task, arg, ofSuccess, and ofError. task is the async function you want to call (of type 'a -> Async<'b>). arg is the parameter of type 'a that you want to pass to the task function. ofSuccess is a function of type 'b -> 'Msg: it will receive the result of the async function and is supposed to create a message, presumably one that incorporates the 'b result. Finally, ofError is a function of type exn -> 'Msg: if the task function throws an exception, then ofError will be called instead of ofSuccess, and is supposed to turn that exception into an Elmish message that your code can handle (presumably one that will log an error to the Javascript console or pop up a notification with Thoth.Toast or something like that).
perform: like either but there's no ofError parameter. Use this if your async command cannot fail (which is never the case with remote API calls, as it's always possible the network is down or your server is unresponsive), or if you just don't care about exceptions and don't mind an unhandled exception getting thrown.
attempt: like either but there's no ofSuccess parameter, so the task function's result will be ignored if it succeeds.
result: this one is completely different. It just takes a single parameter of type Async<'Msg>, i.e. you pass it an async block that is already going to produce a message.
With the code you've written, you would use Cmd.OfAsync.result if you wanted to make minimal changes to your code, but I would suggest using Cmd.OfAsync.perform instead (and upgrading it to Cmd.OfAsync.either once you have written some error-handling code). I'll show you both ways:
type Msg =
// ... rest of your messages go here
| GetLength of string
| LengthResult of int
let update msg model =
match msg with
// ... rest of your update function
| GetLength s ->
let usePerform = true
if usePerform then
model, Cmd.OfAsync.perform server.getLength s LengthResult
else
let length : Async<Msg> = async {
let! length = server.getLength s
return (LengthResult length)
}
model, Cmd.OfAsync.result length
| LengthResult len ->
// Do whatever you needed to do with the API result
printfn "Length was %d" len
model, Cmd.none
And if you were using either (which you really should do once you go to production), there would be a third message LogError of exn that would be handled like:
| LogError e ->
printfn "Error: %s" e.Message
model, Cmd.none
and the Cmd.OfAsync.perform line in the code above would become:
model, Cmd.OfAsync.either server.getLength s LengthResult LogError
That's the right way to handle async-producing functions in Elmish.
Async is one of the places where you use return in F#. So you need to return the length value. Also, Async.StartImmediate returns () (unit). Use something else, e.g. Async.RunSynchronously if you need the extracted value. Depends on what you need to achieve with it.
let length =
async {
let! length = async {return String.length "hello"}
do printfn "%d" length // 5
return length
} |> Async.RunSynchronously
length // val it : int = 5
Btw, you mention fable. So you might be able to use JS promise.
Some resources on Async in F#:
F# Async Guide from Jet
Async Programming
FSharp for Fun and Profit
Microsoft Docs
C# and F# Async
For those who want to call from js code.
// Client code (Compiled to Javascript using Fable)
// ============
open Fable.Remoting.Client
open Fable.Core // required for Async.StartAsPromise
let server = Proxy.create<IServer>
let len_from_fable () =
async {
let! length = server.getLength “hello”
return length
} |> Async.StartAsPromise
call from js
async func() {
let len = await len_from_fable()
print(len)
}
works in fable 3.0.
How do I await an async method in F#?
I have the following code:
type LegoExample() =
let brick = Brick(BluetoothCommunication("COM3"))
let! result = brick.ConnectAsync();
Error:
Unexpected binder keyword in member definition
Note, I reviewed the following link:
However, I only observe the functional technique and not the OOP technique.
you get the error because the let! construct (just like the do!) needs to be placed inside a computational workflow (like async { ...} but there are others - it's basically the syntactic sugar F# gives you for monads - in C# it would be the from ... select ... stuff LINQ came with and in Haskell it would be do ... blocks)
so assuming brick.ConnectAsync() will return indeed some Async<...> then you can wait for it using Async.RunSynchronously like this:
let brick = Brick(BluetoothCommunication("COM3"))
let result = brick.ConnectAsync() |> RunSynchronously
sadly a quick browser search on the page you linked did not find ConnectAsync so I cannot tell you exactly what the indent of the snippet was here but most likely you wanted to have this inside a async { ... } block like this:
let myAsyncComputation =
async {
let brick = Brick(BluetoothCommunication "COM3")
let! result = brick.ConnectAsync()
// do something with result ...
}
(note that I remove some unnecessary parentheses etc.)
and then you could use this myAsyncComputation
inside yet another async { .. } workflow
with Async.RunSynchronously to run and await it
with Async.Start to run it in background (your block needs to have type Async<unit> for this
with Async.StartAsTask to start and get a Task<...> out of it
...
If I've got an async parameterless workflow in F#, is it necessary and/or idiomatic to make that a function, or is it best left as a raw value?
For example if I want to define getRemoteCounterAfterOneSec, polls some remote counter source, should it be
let getRemoteCounterAfterOneSec =
async {
do! Async.Sleep 1000
return! ...
}
or
let getRemoteCounterAfterOneSec () =
async {
do! Async.Sleep 1000
return! ...
}
It seems like they should do the same thing, just the latter has an unnecessary parameter. However I've seen this done both ways in various code. I've also seen places where the behavior ends up different: if using a MailboxProcessor and doing
let myFunc = mailboxProc.PostAndAsyncReply(fun reply -> GetCount reply)
async {
let! count1 = myFunc
let! count2 = myFunc
}
then the mailboxProcessor is only called once; the second time it merely returns the same value calculated in the previous call. However if myFunc is a function then it calls mailboxProcessor twice as you'd expect.
let myFunc() = mailboxProc.PostAndAsyncReply(fun reply -> GetCount reply)
async {
let! count1 = myFunc()
let! count2 = myFunc()
}
Is that a bug in the implementation? What's going on here and what is idiomatic?
When it comes to ordinary asyncs that you define yourself, then adding () has no effect (well, it means that the async that describes a computation is constructed repeatedly, but it has no practical effect).
I sometimes write it just to make my code easier to understand, or when the async is recursive (because then you get a warning when you have a recursive value). So, the following is fine, but it gives you a warning:
let rec loop =
async {
do! Async.Sleep 1000
if 1 > 2 then return 1
else return! loop }
The PostAndAsyncReply method is written a bit differently - and the name tries to reflect that. Normal F# async methods are named AsyncFooBar. This one has PostAndAsyncFooBar to indicate that it first posts and then asynchronously waits, that is something like:
let PostAndAsyncWait () =
post(message)
async { let! sth = wait ()
return sth }
So, here it actually posts outside of the async - this lets you call the function even if you are (syntactically) outside of an async block. And the name tries to be very explicit about this.
(But I would personally prefer if it was all inside async i.e. AsyncPostAndWait).
Suppose that I have the following code:
namespace Library1
open System.Threading.Tasks
open System.Threading
open System.Runtime.Remoting.Messaging
open System
type public Class1() =
let printThread (message) =
printfn "%s %A" message Thread.CurrentThread.ManagedThreadId
let bar =
printThread ("first bar")
async {
printThread ("first async")
do! Async.Sleep(1000)
printThread "last async"
}
member this.X() = bar
I would like to use this class and invoke X from C#. The problem is X returns an Async<'T>. However, it is bad practice to expose F# specific types. So best practice is to return a Task. However Async.StartAsTask is kind of problematic since it will cause the code run in a seperate thread. What I want is I want to return a Task but also it should behave as Async.StartImmediate. Thus the non async part of the code should run in the original main thread. Here I assume I run it from UI thread so that all calls will return the same thread ID. In other words I want a Async.StartImmediate but returning a task.
Is this achieavable ?
You can turn Async<'T> into Task<'T> using the Async.StartAsTask<'T> method.
I'd generally recommend making things easy for the C# users and extend the F# implementation with an additional method that returns Task<'T>. Following the usual naming convention, you can call the F# version AsyncFoo and the C#-friendly version FooAsync.
Looking at your example, I'd go with something like this:
type public Class1() =
let printThread (message) =
printfn "%s %A" message Thread.CurrentThread.ManagedThreadId
let bar =
printThread ("first bar")
async {
printThread ("first async")
do! Async.Sleep(1000)
printThread "last async"
}
member this.AsyncFoo() = bar
/// Expose C#-friendly asynchronous method that returns Task
member this.FooAsync() = Async.StartAsTask(bar)
/// Expose C#-friendly asynchronous method that returns Task
/// and takes cancellation token to support cancellation...
member this.FooAsync(cancellationToken) =
Async.StartAsTask(bar, ?cancellationToken=cancellationToken)
This Works exactly as I want (unlike the question this version returns an int as well which is plus):
type public Class1() =
let printThread (message) = printfn "%s %A" message Thread.CurrentThread.ManagedThreadId
let bar =
printThread ("first bar")
async {
printThread ("first async")
do! Async.Sleep(1000)
printThread "last async"
return 1232
}
member this.convertToTask<'T> (asyn : Async<'T>) =
let tcs1 = new TaskCompletionSource<'T>()
let t1 = tcs1.Task
Async.StartWithContinuations
(
asyn
, (fun (k) -> tcs1.SetResult(k)), (fun exn -> tcs1.SetException(exn)), fun exn -> ())
t1
member this.X() : Task<int> = (bar |> this.convertToTask)
How about defining X like this?
member this.X() =
let t = new Task(fun () -> bar |> Async.StartImmediate)
t.RunSynchronously()
t
As far as I can tell, it does what you want. At least, this C# code:
Console.WriteLine("X " + Thread.CurrentThread.ManagedThreadId);
var c = new Class1();
c.X().Wait();
Thread.Sleep(2000);
prints this output:
X 7
first bar 7
first async 7
last async 11
Here, as seen from C#, X has the signature Task X().
I need to do some setup in a module that I wanted to accomplish by leveraging a do block. Strangely though, my do block never seems to get hit.
Even stranger, If I load the module code into fsi, it does get hit. Here is my example:
Main.fs
[<EntryPoint>]
let main args =
printfn "%b" TestNamespace.M.x
0
TestModule.fs
namespace TestNamespace
module M =
do
printfn "In do"
failwith "Error" // this is line 6
let x = true
When I run the compiled executable I get
>test.exe
true
Why didn't the exception get thrown? If I run the module in FSI by itself I get
In do
System.Exception: Error
at <StartupCode$FSI_0006>.$FSI_0006.main#() in C:\Projects\Personal2\Playground\fsscripts\fsscripts\TestModule.fs:line 6
Stopped due to error
So it got the exception.
I see that in the decompliation that the do initializers get rolled into a seperate class
namespace \u003CStartupCode\u0024fsscripts\u003E
{
internal static class \u0024Library1
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
internal static int init\u0040;
static \u0024Library1()
{
ExtraTopLevelOperators.PrintFormatLine<Unit>((PrintfFormat<Unit, TextWriter, Unit, Unit>) new PrintfFormat<Unit, TextWriter, Unit, Unit, Unit>("In do"));
Operators.FailWith<Unit>("Error");
bool x = M.x;
}
}
}
VS the actual module code:
namespace TestNamespace
{
[CompilationMapping(SourceConstructFlags.Module)]
public static class M
{
public static bool x
{
[DebuggerNonUserCode] get
{
return true;
}
}
}
}
So how do I make sure the do block actually gets executed?
--
Edit, given the above example counts as a simple constant expression so won't produce an observable initialization, why does the following also not work?
[<EntryPoint>]
let main args =
printfn "%d" (TestNamespace.M.x id 1)
0
namespace TestNamespace
module M =
do
printfn "In do"
failwith "Error"
let x f a = f a
This prints out 1 no problem.
Edit, after having re-read Tomas's comments its because a function is considered a constant expression.
For a good explanation of the problem, see the answer to this previous SO question. The important bit says:
the static initializer for the file is executed on first access of a value that has observable initialization
Now, "observable initialization" is somewhat tricky idea, but simple constant initialization definitely does not have observable initialization - that's why the do block is not executed. You can trick the compiler into thinking that there is some imperative action, for example by adding do ():
module M =
do
printfn "In do"
failwith "Error" // this is line 6
let x = (do ()); true
You can get the behavior you want, while maintaining the same public interface, with a class:
type M private () =
static do
printfn "In do"
failwith "Error"
static member val x = true
Here is a clean way to do it.
First, note that if you wanted the initialization code to run every time the function is called, you would do this:
module M =
let init () =
printfn "In init"
let x f a =
init ()
printfn "In x"
f a
So, if you want it to be called just once (static initialization), you can simply remove the () from both places:
module M =
let init =
printfn "In init"
let x f a =
init
printfn "In x"
f a
The nice thing is that you have documented your design that the init code will be called first. If you have several separate blocks of initialization code, it is clear which dependency you are relying on (although the first initialization will execute all such blocks of course).
UPDATE
Here is a version, which works in a Release build too. Not quite so clean, but almost:
module Init =
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let call init = init
module M =
let init =
printfn "In init"
let x f a =
Init.call init
printfn "In x"
f a
Note that init is still a unit value, so Init.call is a non-inlined function that does nothing at all. So there is the overhead of a function call to nothing.
An alternative, which also works but seems a little strange is this:
module M =
let mutable init =
printfn "In init"
let x f a =
init <- init
printfn "In x"
f a
Can anyone improve on this?