It just takes time to defeat the 40+ years of c and c++ dominance.
(Yes, I'm familiar with the rich ecosystem around helping devs not write crummy C. I worked at Coverity at one point. If anything, that gave me enormous fear and respect of the hoops you have to jump through to be reasonably sure C code isn't completely broken.)
Glancing at random C code tells you nothing about what happens with the data flowing into and out of it.
In my experience with it, rustc has been insistent on making me write code that's actually correct. I could translate that code back to C and have better C code than I would likely have written on my own. If there were something similar to `gcc -Werror -Weverything-rust-would-complain-about` — and if that thing were even possible — I very well might stick with C. Oh, and something as fast and ergonomic and informative as rust-analyzer would be hugely welcome.
You have a single line serialization into/from absolutely anything. You have logging, tracing, cli libraries, error handling - most of those are one liners.
You have enums. Enums are business logic. Enums are often the way the world works.
You press enter and it builds, no pre setups, sub modules, cmake files and whatnot.
I like F#, Haskell, Elixir but not Rust.
[0] https://survey.stackoverflow.co/2024/technology#most-popular...
But the moment you search Rust on LinkedIn, you can see the truth.
> Which programming, scripting, and markup languages have you done extensive development work in over the past year, and which do you want to work in over the next year?
It does not ask if you are gainfully employed and using this language for your job.Also, in the same results, just above Rust, I see:
> PowerShell 13.8%
<sarcasm>
So, I guess that we can safely say that Microsoft PowerShell is still more popular than Rust.
</sarcasm>The annual survey is very popular in the Rust community. Its results are often used for advocacy. Participation by Rust developers is very high. So what you have is a classic case of a selection bias.
Compared with C/C++, Java, C#, Javascript, Python, Typescript, PHP, all the rest can be considered niche.
With which language are you comparing with?
Because there's afaik csproj and maybe .sln
and both of them are let's be frank - foundational for almost all projects that arent just hello world.
Otherwise you end up with some cmakes or something similar that want to achieve something similar
Oh man, that is poignant :( They always say they do in the job description, but it always a different story once you get there.
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.
the F# equivalent is
`let! post = _postService.getById id`
The controller handler is also the same. It will be marked with `async` keyword in C# and `task` CE in F#
In both languages these patterns make up for the absence of typeclasses to express things like a functor, applicative, monad, comonad, etc.
[1]https://ecma-international.org/wp-content/uploads/ECMA-334_7...
For the specific case of C# use of await it is unfortunate that C# didn't design this feature with F# interop in mind so it does require extra steps. F# did add the task builder to help with this so the 'await' is replaced with a 'let!' within a task builder block.
let getById(id:int) : Task<string> = failwith "never"
let doWork(post:string) : unit = failwith "never"
let doThing() = task {
let! post = getById(42);
doWork(post); }
Alternatively the task can be converted to a normal F# async with the Async.AwaitTask function. let getPostById1(id:int) : Async<string> = async { return! getById(id) |> Async.AwaitTask }
let getPostById2(id:int) : Async<string> = getById(id) |> Async.AwaitTask
let getPostById3 : int -> Async<string> = getById >> Async.AwaitTaskThe author of the original comment, however, does not know this nor tried verifying whether F# actually works seamlessly with this nowadays (it does).
Writing asynchronous code in F# involves less syntax noise than in C#. None of that boilerplate is required, F# should not be written that way at all.
Personally, I'm just annoyed by never-ending cycle of ".NET is bad because {reason x}", "When was this the case?", "10 years ago", "So?".
Like in the example above, chances are you just won't see new F# code do this.
It will just use task { ... } normally.
let foo id = async {
let! bar = getBar id
return bar
}
I would prefer let async foo id =
let! bar = getBar id
bar
or even something like let async foo id =
getBar! id
So that computation blocks don't feel like you're switching to an entirely different language. Just wrap the ugliness in the same syntactic sugar that C# does. As it is, C# can achieve arrow syntax with async methods more elegantly than F# can: async Task<string> foo(int id) => await getBar(id);
This, to me, is also part of a larger problem of F# introducing unique keywords for specific language functions instead of reusing keywords, like member this.Foo = ...
and member val Foo = ...You don't even have to use the computation block for that and can use the built in functions as I mentioned earlier and gave 3 examples of.
You're both complaining about extra keywords while trying to make the case of adding yet another one. Thus your complaint boils down to F# not picking the exact keywords that you like - that the language is not specialized to exactly how you want to use it. In language design there are always tradeoffs but I'm unable to see how your suggestions would improve the language in the general case or even in your specific case.
Computation expressions are a generalized concept which are there to add the exact kind of syntactic sugar that you're after. It's better than C# in that you can create your own as a first class concept in addition to using the built in ones. It's there for the exact purpose of creating mini-embedded DSLs, the very thing you're complaining about is the exact point of it.
F# is not for everyone, nor should it be.
I did no such thing. async is already a keyword in F#, I'm just saying they should drop the brackets and remove the required return statement.
> In language design there are always tradeoffs but I'm unable to see how your suggestions would improve the language in the general case or even in your specific case
It would make the language easier to read, for one, and would reduce the amount of specialized syntax needed for specific features. It would preserve the original ML-style syntax for an extremely common operation and not force users into wrapping anything upstream of an async call in a computation block, which is the ugliest syntax feature of F#
> Computation expressions are a generalized concept which are there to add the exact kind of syntactic sugar that you're after
I understand that, and my argument is they failed to do so. The syntax looks bad. They could keep it for all I care, but they should add even more sugar on top to make it not look so bad.
The return statement is only required if you want to return something form the computation expression. In your example you use async { let! x = f(); return x}, which can be reduced to async { return! f()}, which can be reduced to f().
The rest is your opinion that I don't agree with.
There are multiple alternate asynchronous computation expression implementations which give different ergonomics and behavior (like https://github.com/TheAngryByrd/IcedTasks). There's an entire CE extension to specifically enable this kind of convenience and flexibility too: https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0...
None of this is possible in C#, at least without jumping through many hoops and ending up with extra boilerplate (and this is okay, C# has enough of its own complexity). As cjbgkagh noted, providing this type of control is the whole point and what makes F# so powerful.
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).ResultFor F#, projects are needed to make full applications or libraries. Otherwise, you can simply write F# scripts with .fsx and execute them via 'dotnet fsi {SomeScript.fsx}'.
(obviously you can also specify dotnet fsi as shebang and integrate these scripts into general scripting on Unix systems - it's very productive)
Last time I tried C++ with Copilot it was terrible.
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.