←back to thread

Why F#?

(batsov.com)
447 points bozhidar | 1 comments | | HN request time: 0.209s | source
Show context
rockyj ◴[] No.43546371[source]
I did try F#, but I was new to .NET ecosystem. For 1 "hello world" I was quite surprised by how many project files and boilerplate was generated by .NET, which put me off.

I am all for FP, immutable, and modern languages. But then where are the jobs and which companies care if you write good code?

Now everyone wants languages which are easy to use with AI, while reducing workforce and "increased productivity". I have been programming for 20 years and know 4-5 languages, in India it was worse but in EU at-least I can make a sustainable living by writing Java / TypeScript. I cannot even find jobs with Kotlin + TypeScript which pay well, forget getting jobs in Elixir / Clojure / F# (there maybe a handful of opportunities if I will relocate for around 70K/year). That is why I have mostly given up on learning niche languages.

replies(11): >>43546449 #>>43546522 #>>43546629 #>>43546648 #>>43546914 #>>43546918 #>>43547243 #>>43547274 #>>43547691 #>>43548828 #>>43553311 #
shortrounddev2 ◴[] No.43547274[source]
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.

replies(4): >>43547546 #>>43547687 #>>43548815 #>>43552613 #
1. throw234234234 ◴[] No.43552613[source]
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

  task { return! _postService.getById(id) }
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.

  public async Task<Post> GetPostById(id) => await blogPostService.getPostById(id);

  // This is not entirely eq - since tasks are hot
  this.GetPostById(42).Result