Comment by shortrounddev2
Comment by shortrounddev2 3 days ago
I like F#'s syntax when all you're doing is pure logic. But when you have to interface with any IO like a database or REST call or something, you have to abandon the elegance of ML syntax and use these ugly computation blocks. In C# you can do something like this:
var post = await _postService.getById(id);
in F# the equivalent is basically let getPostById id = async {
let! post = blogPostService.getPostById id
return post
}
let post = getPostById 42 |> Async.RunSynchronously
But not really, because RunSynchronously isn't the same thing as `await`. Realistically if you wanted to handle the result of an async computation you would need to create continuations. F# isn't the only ML-family language to suffer from this; Ocaml does as well. It always seemed to me like the pattern with any asynchronous operations in F# is to either:1. Do all logic in ML-syntax, then pass data into a computation block and handle I/O operations as the last part of your function, then return unit OR
2. Return a C#-style Task<> and handle all I/O in C#
Either way, ML-style languages don't seem like they're designed for the kind of commercial CRUD-style applications that 90% of us find ourselves paid to do.
I find it personally better for CRUD applications than C# and I've written my share in both languages. Your syntax comparisons aren't exactly comparable in the sense that you haven't put in the wrapping/boilerplate around the C# code - you can't just await anywhere. You are also using an async which to run needs to know which context - this can be nice when you don't want to run the composed Task/Async on the current sync context. These days you stick to tasks if you want C# like behavior - and there's libraries to take away some SyncContext overload via custom F# CE's if you want.
The equivalent C# to your F# would be
Which is somewhat pointless anyway - just return the task from postService directly. There's also no need to run the async synchronously then - Async allow you to run the logic on task, thread, sync over and over - a very different model than tasks.To make C# comparable to your F# code (tasks are not the same so not quite true) you would need to define a method around it, and find a way if you want to run the resulting Task synchronously to do that safely.