Reputation: 3509
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?
Upvotes: 4
Views: 94
Reputation: 243051
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
).
Upvotes: 2