-
Notifications
You must be signed in to change notification settings - Fork 22
Description
I propose we add syncTask builder (similar to backgroundTask), which will greatly lower F# entry barrier. Today most of the .NET API's become asynchronous and most of 10-liner "Hello world" apps require unnecessary cognitive load of adding .GetAwaiter().GetResult() or Async.runSynchronously, for example
(task {
let tempFilePath = Path.GetTempFileName();
do! File.WriteAllTextAsync(tempFilePath, "Hello, World!")
let! readContent = File.ReadAllTextAsync(tempFilePath)
printfn $"File content: %s{readContent}"
}).GetAwaiter().GetResult()New builder will allow to simplify that
syncTask {
let tempFilePath = Path.GetTempFileName();
do! File.WriteAllTextAsync(tempFilePath, "Hello, World!")
let! readContent = File.ReadAllTextAsync(tempFilePath)
printfn $"File content: %s{readContent}"
}This problem doesn't exist in C# due to ability to write await in the top level file.
The existing way of approaching this problem in F# are:
- Using shorthand lambdas
task {
let tempFilePath = Path.GetTempFileName();
do! File.WriteAllTextAsync(tempFilePath, "Hello, World!")
let! readContent = File.ReadAllTextAsync(tempFilePath)
printfn $"File content: %s{readContent}"
}
|> _.GetAwaiter().GetResult()- Using custom operators
let inline (~+) (t: Task<'a>) : 'a = t.GetAwaiter().GetResult()
+task {
let tempFilePath = Path.GetTempFileName();
do! File.WriteAllTextAsync(tempFilePath, "Hello, World!")
let! readContent = File.ReadAllTextAsync(tempFilePath)
printfn $"File content: %s{readContent}"
}- Writing custom builders
type SyncTaskBuilder() =
member inline _.Bind(t: ValueTask<_>, cont) =
task.Bind(t, cont)
member inline _.Bind(t: Task<_>, cont) =
task.Bind(t, cont)
member inline _.Zero() =
task.Zero()
member inline _.Delay(f) =
task.Delay(f)
member inline _.Combine(t1, t2) =
task.Combine(t1, t2)
member inline _.While(cond, t) =
task.While(cond, t)
member inline _.Return(x) =
task.Return(x)
member inline _.ReturnFrom(t) =
task.ReturnFrom(t)
member inline _.Run(f) =
task.Run(f).GetAwaiter().GetResult()
let syncTask = SyncTaskBuilder()Pros and Cons
The advantages of making this adjustment to F# are easier reading and writing code for newcomers, but also for F# demos with single-line files
The disadvantage of making this adjustment to F# is making easier to write blocking asynchronous code.
Extra information
Estimated cost (XS, S, M, L, XL, XXL): S
Related suggestions:
#1022
#1042
#581
Affidavit (please submit!)
Please tick these items by placing a cross in the box:
- This is not a question (e.g. like one you might ask on StackOverflow) and I have searched StackOverflow for discussions of this issue
- This is a language change and not purely a tooling change (e.g. compiler bug, editor support, warning/error messages, new warning, non-breaking optimisation) belonging to the compiler and tooling repository
- This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it
- I have searched both open and closed suggestions on this site and believe this is not a duplicate
Please tick all that apply:
- This is not a breaking change to the F# language design
- I or my company would be willing to help implement and/or test this
For Readers
If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.