F# was for me the best functional language when I looked at rewriting a Ruby on Rails app.
I wanted to go with a functional language, as it seems to better fit my thinking and reasoning, and I looked at Haskell, Ocaml, Scala, F#.
Being a stranger to Microsoft technologies, F# was the least likely to be chosen, but easily became the first choice.
Haskell's purity made it hard to adopt (for me), Ocaml's ecosystem is subpar (there wasn't even a clear choice for a library to interact with postgresql, I couldn't install the latest version due to its reliance on an obscure tool whose name I forgot and didn't get help on the forum), and Scala is seems complex....
F# was surprisingly easy to get started with. The community is mis-managed by a corporate-minded approach (requiring people to become member of the F# software foundation to get access to the official slack!), but its members are friendly, smart and ready to help. The ecosystem is great with access to all the dotnet libraries (some complain there's a mismatch as most of those are developed for use with C#, but I rarely got in trouble for using them).
There are also great libs and frameworks available. Like https://github.com/SchlenkR/FsHttp to easily interact with http servers, to the point that I find it easier to use than a dedicated library. Or https://github.com/CaptnCodr/Fli , to run commands. And last but not least, https://www.websharper.com/ is the best web framework I have encountered across all ecosystems. Their reactive approach to web ui really allows me to develop complex interfaces in a maintainable way.
This became a longer message than I thought, probably due to my enthousiasm for the language. For complete transparency, the situation is not perfect, and in my experience the tooling is not the best.
Curious since you don't expand on it on the blog: in what way did Haskell's purity make it difficult to you?
Having used Haskell in production for a bit now, I don't even notice its purity. Most functions are in some kind of I/O context making it similar as other languages, except with the option of running without I/O capabilities for functions that shouldn't need it.
internet_points 23 hours ago [-]
For me, Haskell's image and ideal of purity are what made it difficult when I started out. I tried learning the language by reimplementing a program I'd previously done imperatively, that was (in hindsight) obviously hard to do in a plain pure way, ended up learning about zippers and knot-tying to do something in a less efficient and more confusing way than just using something like STArray because I had this idea from reading about Haskell that this was not only a good way to do things, but would be magically fast because GHC. (It was not.)
These days I'd just do such a task more-or-less imperatively in Haskell, and I would be well guided by the types in doing so. But I also feel like you have to make a few such mistakes if you want to get a good intuition and taste for when it's good do things purely and when imperatively.
raphinou 1 days ago [-]
I honestly don't remember as it was +/-6 years ago. I had started learning Haskell and got to that conclusion. Maybe that I am now more versed in FP I would arrive at another conclusion? I don't know.
Another thing that was hard to grasp for me were the special operators like =<<, ., $, etc. I was using Xmonad, but those operators create a barrier to understanding exactly what happened in the file.
In the end, F# was in my (personal) experience much more approachable, and it let me learn the functional concepts along the way.
giraffe_lady 23 hours ago [-]
You gotta remember people are often picking languages based on what they can easily find out about it and extrapolating/guessing about what problems they'll run into with their expected use.
A few years ago on here I had an interesting conversation with someone who wasn't going to use rescript for something because they didn't like how it handled object types. I can't remember ever using an object type in rescript; we all just convert js objects to record type in the extern binding. But that's not information easily available to someone who has never used the language.
Same thing here I think. If you don't already have familiarity with this paradigm, it's hard to imagine what using an IO monad for side effects is like. It's not easy to tell how hard it'll be to learn it, how much it may affect the rest of your code, etc. It's easy to imagine someone (shit even me a few years ago) going "eh I'll take the language with the big easy escape hatches just in case."
fredrikholm 13 hours ago [-]
> You gotta remember people are often picking languages based on what they can easily find out about it and extrapolating/guessing about what problems they'll run into with their expected use.
This is a good observation.
As someone who writes a lot of Lisp, I'm inclined to agree as the amount of people that have never written any Lisp yet immediately reject it over syntax over fears that it somehow hampers development is a (to me) surprisingly large number of people.
If I recall correctly, one of the motivating factors for Rescript was to reduce the perceived/real distance between Reason and JS in order to attract more JS devs, as Reason was so heavily associated with OCaml.
ninetyninenine 4 hours ago [-]
Haskell taught me the important differences between IO and parity and forever influenced the way I program.
Even so the complexity here and the sheer number of mind bending concepts makes me not want to use it.
blatantly 10 hours ago [-]
What about libraries though? They might force you to use certain monads rather than IO?
kqr 8 hours ago [-]
The libraries I use either have, or at least allow, IO at the base of their transformer stacks, so any IO action is a liftIO away.
mike1o1 1 days ago [-]
There was a large group of folks that left Ruby on Rails for Elixir (even has a similar looking syntax), yet it wasn't on your list of languages to consider. Just curious, was there a particular reason?
raphinou 1 days ago [-]
I should have mentioned in the message, but I was looking for a strongly typed language.
I was an avid-user of dynamically-typed languages, but that particular Ruby on Rails app became unmaintainable, and part of the culprit was due to the dynamic typing. I hoped that using a statically typed language would make it easier to maintain a complex app in the long term.
And I must say that it totally materialised, to the point that I don't want to develop in dynamically typed languages anymore.
Here's an example: as I said in my original message, I was a complete stranger to the dotnet ecosystem, and I learned the F# language at the same time. And I decided to develop the app as a library project to be used by the web app. I completely missed the prevalence of the async approach in the dotnet, and all my code was synchronous. One day, about half-way in the project, I realised I needed to switch to async code. Had this happened in a dynamically typed project, it would have been hell for me. Maybe it's me that can't grasp a project well enough, but I need the type-guardrails to find my way in large refactorings. And with the strong types, large refactorings can be done confidently. They don't replace tests, but make the refactoring process much more smooth.
The app is open source and its code is at: https://gitlab.com/myowndb/myowndb
It doesn't have a lot of users, not the least due to lack of marketing and polishing the user experience. But I am satisfied of what I learned developing it!
DonaldPShimoda 1 days ago [-]
This is a really minor point, but "strongly typed" and "statically typed" are not interchangeable terms. In the context of your comments here, you are exclusively interested in the static nature of the type system, rather than anything about the "strength" of it (which is something totally different and inconsistently defined).
throwaway2037 11 hours ago [-]
Can you explain more about strongly typed vs statically typed?
saghm 11 hours ago [-]
Typically, "static typing" refers types being checked at compile time rather than runtime; in other words, the analysis can happen before the program is run, which gives you some degree of confidence in what the behavior will be when actually running it. The opposite of this is "dynamic typing", which means that the type-checking happens while the program is running, so you don't have the up-front guarantee that you won't end up having an error due to the wrong type being used somewhere. In practice, this isn't a strict binary where a language has to be 100% static or 100% dynamic. For example, Java is mostly statically typed, but there are some cases where things are a bit more dynamic (e.g the compiler allowing certain casts that might not end up being successful at runtime, at which point they throw an exception). On the other hand, Python traditionally has been a dynamically typed language, but in recent years there have various efforts to allow type annotations that allow checking some things in advance, which moves it a bit in the static direction (I'm not familiar enough with the current state of things in the ecosystem to have any insight into how much this has moved the needle).
On the other hand, "strong typing" isn't as quite as standardized in type systems terminology, but broadly speaking, it tends to be used to describe things like how "sound" a type system is (which is a well-defined concept in type systems theory), whether or not implicit type coercions can occur in the language, or other things that roughly translate to whether or not its possible for things to get misused as the wrong type without an explicit error occurring. Two examples that are commonly cited are JavaScript[0], with its sometimes confusion implicit conversions to allow things like adding an empty object and an empty array and getting the number 0 as the result (but not if added in the other order!) and C, with it being possible to interpret a value as whatever the equivalent underlying bytes would represent in an arbitrary type depending on the context its used.
[0]: I normally don't like to link to videos, but this famous comedic talk demonstrating a few of these JavaScript quirks is so thoroughly entertaining to watch again every few years that I feel like it's worth it so that those who haven't seen it before get a chance: https://www.destroyallsoftware.com/talks/wat
baq 11 hours ago [-]
strong typing: 2 + "2" is an error (e.g. Python vs JS)
static typing: 2 + "2" does not compile/parse (e.g. Python vs mypy, Typescript vs JS)
this is a very simplistic example, but should get you to feel the difference.
volemo 4 hours ago [-]
> static typing: 2 + "2" does not compile/parse (e.g. Python vs mypy, Typescript vs JS)
I think this example is not correct, because static typing doesn’t affect how values of different types interact. And while I don’t know of any staticly typed language where specifically `2 + “2”` is a valid expression, statically typed languages definitely can be weakly typed: the most prominent example is C where one can combine values of different types without explicitly converting them to the same type (`2 + 2.0`).
I believe strong/weak and static/dynamic are orthogonal. And my examples are:
- Strong: `2 + “2”` is a error,
- Weak: `2 + “2”` makes 4 (or something else, see the language spec),
- Static: `var x = 2; x = “2”` is an error,
- Dynamic: `var x = 2; x = “2”` is fine.
sparkie 2 hours ago [-]
Dynamic typing can forbid the latter (at runtime), but it's implementation dependent. There's a further distinction, Latent typing, which is where types are associated with values rather than variables.
But a dynamic language can have types associated with variables, and it can forbid changing those types after their types have been checked the first time.
hoseja 9 hours ago [-]
weak typing: 2 + "2" is 22
RUnconcerned 6 hours ago [-]
could also be "4" or 4! 4 seems like it would be the most evil option, honestly
pjc50 6 hours ago [-]
The real evil option is C: 2+"22" = 0, 4+"4" = undefined behavior and probably the value of some other variable.
manwe150 5 hours ago [-]
I think you meant: "22"+2 = "", and it is not UB to make the second pointer, only to use it
or the most sane, depending on context... e.g. awk and perl do this.
raphinou 1 days ago [-]
You are absolutely right. Thanks for pointing it out.
DonaldPShimoda 1 days ago [-]
Sure thing. Cheers!
tasuki 1 days ago [-]
These days there's Gleam[0], as a strongly typed alternative for the BEAM virtual machine. Of all the languages I haven't used yet, it seems to hit the safe + minimalistic + productive sweet spot the best. (Yes the C-inspired syntax is slightly off-putting, but syntax is the least important aspect of a language.)
I am also keeping an eye on gleam! I also regret that they left the ml syntax behind, but as you say it shouldn't be a blocking factor.
If they adopt computation expressions and make otp a priority it would probably come beside fsharp in my toolbox!
neonsunset 1 days ago [-]
Gleam, much like any language which primarily targets BEAM, is slower by an order of magnitude or two when compared to F#.
no_wizard 1 days ago [-]
The appeal is the runtime model. I can’t readily verify if BEAM languages are meaningfully slower or really slower at all but let’s take the premise for the sake of argument.
Even if is slower, the runtime model is incredibly resilient and it’s cheap to scale up and down, easy to hot update, and generally does asynchronous work extremely well across a lot of different processes.
F# has really good async ergonomics but it doesn’t have the same task/processing flexibility and Websockets are kind of a pain compared to elixir or even erlang
CharlieDigital 9 hours ago [-]
.NET's SignalR is actually quite good. Strongly typed message hubs on the server[0]. Wide client support. Azure SignalR[1] if you don't want to own the infrastructure to scale web sockets.
given this is about F#, the question is how ergonomic is it to use this in F#?
In the past, I found it wonky
davydog187 7 hours ago [-]
For most of the workloads you’re putting on the BEAM, they are IO bound and this is not of any consequence
asadbeksindar 13 hours ago [-]
Hey, thank you for sharing your app's source code. I'll definitely check it out, I was really looking for such apps on F# open source projects!
breadwinner 1 days ago [-]
Apache Spark, Delta Lake are written Scala. Being JVM based, it has a large ecosystem. Scala seems like a better choice than F#.
raphinou 1 days ago [-]
I'm sure it can be the better choice, but for me it was not.
It seems there was some incompatibility between me and Scala. I find it such a complex language and I never managed to wrap my head around it.
As I said F# was my last choice at the start of my evaluation, and Scala was high on the list due to the Java ecosystem. But in the end it didn't work out for me.
F# on the JVM would be great though!
frakt0x90 1 days ago [-]
I agree with you. I tried Scala for weeks and found it far too complex. Every line I wrote, I felt there were 5 different ways of doing it and I didn't know if I was choosing the right one. Scala tries to be too many things at once imo.
hurril 1 days ago [-]
It runs on .NET, for god's sake. This is not a small platform.
michaelcampbell 24 hours ago [-]
Basically everything runs on an OS, which is even more complex.
jayd16 3 hours ago [-]
They mean ecosystem.
flakiness 1 days ago [-]
Is F# easier to learn than Scala? (I know a bit of Scala (in the old 2.x days) but have no knowledge of F#.)
raphinou 1 days ago [-]
It definitely was for me!
The syntax is simple, it is functional first but is not pure.
I started with zero experience with ml languages and got productive fast enough to enjoy it. Of course my early f# code could be improved, but it was working and while writing the code the language didn't feel like a barrier.
One caveat though: it seems FP matches my way of thinking. As an example, I always liked recursion, while some others saw it as complexifying things.
Try fsharp as fsx scripts to avoid boilerplate (see blog post linked in other comment) and you'll rapidly feel if you like it or not.
ecshafer 1 days ago [-]
I have done a bit of both Scala and F#, I think F# is a good bit easier to learn. Scala I think mixes OOP concepts and mutability in a bit less gracefully.
neonsunset 1 days ago [-]
At least the tooling should be way nicer. It is way more of an OCaml language than Scala. Also much like having to deal with JVM ecosystem in Scala, you'd need to deal with .NET ecosystem in F#. In my opinion, the latter can be an advantage. F# has a lot of depth but you do not need to grasp it fully to be productive with it.
spooneybarger 23 hours ago [-]
It was for me.
apwell23 10 hours ago [-]
i've used scala for over 8 yrs everyday and i agree with your assessment.
Even intellij has no idea sometimes about what the hell is going on. It throws up compile errors when there none.
michaelcampbell 24 hours ago [-]
Is Frege still being developed?
innocentoldguy 1 days ago [-]
I think Clojure is the better option if you want to do FP using the JVM ecosystem. The problem (for me, anyway) I've run into with Scala is that it supports both functional programming and object-oriented programming. Every code base I've worked on in Scala has ended up being a hodgepodge of both, which I find annoying.
However, the best functional programming language is, of course, Elixir. :D
dkarl 1 days ago [-]
> Every code base I've worked on in Scala has ended up being a hodgepodge of both
Is there something about that that has bothered you? Working in Scala codebases, I've found the best ones to work in are the ones that embrace Scala's multiparadigm nature. When programmers try to solve every problem with OO, they end up adding more and more layers to get the job done. When programmers try to solve every problem with FP, they end up resorting to sophisticated techniques that are unapproachable for other engineers. I think the simple parts of OO and the simple parts of FP go much, much further together than simple OO or simple FP can go by themselves. Have you seen something different?
vips7L 2 hours ago [-]
I really think this is where Kotlin is going to excel; multi-paradigm, multi-platform. Scala's community went too hard into FP and type-golfing to make it approachable.
raphinou 1 days ago [-]
Elixir getting a strong type system is interesting, but watch out for gleam though
Gleam lacks lisp-style macros, and its implementations of BEAM and OTP are not exhaustive. For example, Gleam does not support:
- Hot updates.
- Full distributed system support.
– Low-level process manipulation.
- Named processes.
- Advanced supervision strategies.
- Behaviours other than GenServer.
- Type-safe distributed messaging.
- And several other things that I value in BEAM and OTP.
I can't justify trading the full power of BEAM and OTP for static typing. To be fair, though, I've written a lot of code in both statically and dynamically typed languages, and static typing isn't something I value much (to the point that you might say I don't care about it at all :D).
raphinou 1 days ago [-]
I knew otp was still suboptimal in gleam, but thanks for mentioning all these additional points!
Funny how preferences and priorities vary among devs, I need my static type system! :-)
But note even in static type systems there are variations. I'm talking about an hindley milner type system with its type inference like the one in fsharp
felixyz 9 hours ago [-]
My current preference is to use Elixir and its great ecosystem as the shell for my project, and implement the core business logic in Gleam.
throw234234234 20 hours ago [-]
Evaluated F# vs Clojure. Speed of certain algorithms just lacked for me. Value types particularly in tail recursive stacks shines in F# compared to the JVM in general. As usual YMMV
michaelcampbell 24 hours ago [-]
Isn't Clojure similarly (or even moreso) multiparadigm?
lucyjojo 19 hours ago [-]
i don't think it is. i would say it is functional + bridges to the jvm (which is why it has been ported to many other platforms... there is not that much stuff in the language itself).
it is functional (value) programming first. there are tools to hook in the object jvm stuff but this is not the natural grain of the language.
clojure is pretty much all values and functions (and some macroes).
+ some concurrency stuff
there is no class, there is no inheritance, you don't even have information hiding (no private etc.). you have protocols and multimethods.
(well technically there is private because java but it is not obvious to use and not what you expect, you will very rarely see that in clojure codebases)
honestly it is a nice small yet powerful language, with not too many kludges. my personal coding is either clojure or rust (which has way more kludges, but better than the other stuff in the typed fast compiled world at least for me).
bozhidar 1 days ago [-]
Great story! Thanks for sharing it!
rockyj 1 days ago [-]
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.
8s2ngy 1 days ago [-]
I understand your perspective. I like to view niche languages as a medium for learning. For instance, I enjoy using Rust in my personal projects—even if many of these projects may never be released—because the lessons on immutability, functional programming constructs, and trait-oriented programming significantly enhance my day-to-day work. Therefore, I believe that learning niche languages, even in the absence of a robust job market, is worthwhile.
jen20 1 days ago [-]
I'm not sure I'd call Rust a "niche language" any more (perhaps in ~2018) - it's in common use across many big technology companies.
homebrewer 1 days ago [-]
It is extremely niche outside of this bubble.
mmoskal 1 days ago [-]
According to Stack Overflow developer survey [0] Rust is at 12.5%, roughly a half of C# or Java and a quarter of Python. Also more than twice Ruby. So definitely not niche.
> 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>
winrid 11 hours ago [-]
Powershell is probably more popular, it's used a lot for IT stuff so we never hear about it but it's there.
askonomm 23 hours ago [-]
In my mind not niche means having jobs, and Rust has no jobs, not in any meaningful amount at least, and none at all in most countries. That puts it deep in the niche category for me.
DeathArrow 11 hours ago [-]
It's popular in the "let's rewrite X in Rust" community which are very actively posting on HN, Reddit and wherever they can. That gives the impression it is not niche.
But the moment you search Rust on LinkedIn, you can see the truth.
trott 3 hours ago [-]
> According to Stack Overflow developer survey [0] Rust is at 12.5%, ... So definitely not niche.
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.
sterlind 1 days ago [-]
MS is starting to use Rust pretty extensively internally. That's a lot of developers outside the "bubble."
vlovich123 1 days ago [-]
F# will likely remain niche forever. It’s likely that Rust will not given its growing and accelerating adoption by Microsoft, Google and the Linux Kernel.
It just takes time to defeat the 40+ years of c and c++ dominance.
johnisgood 1 days ago [-]
Personally I will always prefer C's simplicity to Rust's complexity. Could be just me.
kstrauser 1 days ago [-]
I find Rust vastly simpler than C. If the code compiles, it's probably a valid expression of the business logic I encoded. I might've screwed up that logic, of course, and no language can prevent me from messing that up. I know! Many have tried, and I've defeated them with my ability to misrepresent my ideas! But at least with Rust, I'm reasonably confident that the code will actually do the thing I asked it to do. I'm never confident like that with C until I've run it a few hundred times without crashing.
(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.)
dboreham 7 hours ago [-]
This seems...a very contrarian sentiment. Imho while C might lead you to create slightly fragile code once in a while, Rust is something like two orders of magnitude more complex.
aldanor 2 hours ago [-]
Rust is like two orders of magnitude more simple (if you're not going to delve into its darker corners).
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.
ninetyninenine 4 hours ago [-]
No I know what he’s saying. C is not “slightly fragile code once in a while”. When you up the complexity of the code and the amount of code and the people working on the code the fragility becomes pervasive.
kstrauser 4 hours ago [-]
That's a huge part of it. If I stumble across random Rust code, I can assume that it's using typed data correctly, that it's not accessing freed memory, that it's not allocating but never freeing, that length checks are being enforced, etc. If they weren't, it wouldn't even compile (and the compiler would explain why).
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.
vlovich123 20 hours ago [-]
Rust like any language can be as simple or as complex as you want it to be. The complexity raises with the performance of the code you write but that’s also true of C. Unlike C that complexity is combined with guarantees that your code won’t crash in weird and unpredictable ways.
DeathArrow 11 hours ago [-]
I will take C, C++ or Zig over Rust any day. For some people, like me, the Rust way of doing things isn't a good fit. It's not a model I enjoy working with.
I like F#, Haskell, Elixir but not Rust.
DeathArrow 11 hours ago [-]
Just look at the job market. There are far more jobs for Go programmers and Go isn't particularly huge.
Compared with C/C++, Java, C#, Javascript, Python, Typescript, PHP, all the rest can be considered niche.
tester756 1 days ago [-]
>" I was quite surprised by how many project files and boilerplate was generated by .NET, which put me off.
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
owenm 1 days ago [-]
I hear you on the opportunity side and I can't see that changing. The good news is in recent releases there's a lot less boilerplate - "dotnet new console -lang F#" results in two files, a short fsproj file and a single line of Hello World.
Foofoobar12345 1 days ago [-]
F# is quite usable with AI. All AI models are perfectly capable of generating idiomatic F# code. In fact, because it has a nice type system, if you ask the AI to model the problem well with types before implementing, hallucinated bugs are also easier caught.
elcritch 1 days ago [-]
Same with Nim. It works surprisingly well with AI tools. I think both have more straightforward syntax so it’s easy to generate. I’m curious how more complex languages do like C++ / Rust.
Last time I tried C++ with Copilot it was terrible.
KurtMueller 17 hours ago [-]
I find F# easy to use with AI, mainly because it's statically typed (which results in compiler errors when the LLM generates non-working code) and it's very expressive, which allow me to more easily comprehend what the LLM is trying to do.
raphinou 1 days ago [-]
It is possible to start your project with the script possibilities offered by F# (as mentioned in the blog post).
It is absolutely a viable approach and I even blogged about it a couple of months ago: https://www.asfaload.com/blog/fsharp-fsx-starting-point/
sodapopcan 1 days ago [-]
> But then where are the jobs and which companies care if you write good code?
Oh man, that is poignant :( They always say they do in the job description, but it always a different story once you get there.
djha-skin 1 days ago [-]
I learn them as a fun hobby, with no salary expectations. It keeps the dream alive, and I learn a lot from the Common Lisp community that I do use in my job.
afavour 1 days ago [-]
Opportunities do exist, even when they’re few and far between. I learned Rust in my spare time because I was really interested in it. Then we stumbled across something that would have really benefitted from a cross platform library and lo and behold, I got to use my Rust knowledge, even though the vast majority of my day job doesn’t use it.
shortrounddev2 1 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.
throw234234234 19 hours ago [-]
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
cjbgkagh 1 days ago [-]
F# is a big language, it is a ML multi paradigm language that interoperates with C# so there is a lot of necessary complexity and many ways to do the same thing. A strong benefit of this is the ability to create a working functional paradigm prototype that can iteratively be refined to a faster version of itself by hot spot optimizing the slower parts with equivalent highly mutable functions while staying within the same language. Similar how one would use python and C++ and over time replace the python code with C++ code where performance is important.
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.AwaitTask
neonsunset 1 days ago [-]
It is best to just use task CE full-time unless you need specific behavior of async CEs.
The 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.
cjbgkagh 1 days ago [-]
F# is a big language so I think it is to be expected that beginners will not know these things. I don't think the fix is to simplify F# we should just understand that F# is not for everyone and that is ok.
neonsunset 1 days ago [-]
This is perfectly fine, but I think it's better to be unsure about specific language feature than confidently state something that is not correct (anymore).
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.
shortrounddev2 23 hours ago [-]
I understand that you CAN do this, I'm saying that it makes your code look like shit and takes away some of the elegance of ML
cjbgkagh 22 hours ago [-]
Are you saying you prefer Ocaml to F# or C# to F#? Your example was indeed inelegant but it is also poorly designed as you take 4 lines to reproduce a function that is already built in, people can poorly design code in any language.
shortrounddev2 6 hours ago [-]
I'm saying that I wish computation blocks looked better in F#. Instead of:
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:
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 = ...
cjbgkagh 4 hours ago [-]
Your criticism is rather incoherent and it is difficult for me to make sense of it.
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.
shortrounddev2 3 hours ago [-]
> You're both complaining about extra keywords while trying to make the case of adding yet another one
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.
cjbgkagh 3 hours ago [-]
'async' is not a keyword in F#, it's a builder instance no different to the ones that you can create. It's just built in to the standard library.
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.
shortrounddev2 1 hours ago [-]
The distinction in this case is utterly meaningless. This is about the ergonomics of the language. Which are lacking the minute to break out of pure functional land
cjbgkagh 32 minutes ago [-]
I disagree with both of your statements
22 hours ago [-]
neonsunset 23 hours ago [-]
Please stop insisting on this. Task CE exists since F# 6.0 and handles awaiting the CoreLib Tasks and ValueTasks without any ceremony.
malakai521 1 days ago [-]
`var post = await _postService.getById(id);`
the F# equivalent is
`let! post = _postService.getById id`
alternatex 1 days ago [-]
You're missing the task {} block
neonsunset 1 days ago [-]
This assumes the context is already a task computation expression, which is what you'd have in asynchronous code.
sWW26 11 hours ago [-]
and the C# is missing the `async Task` boilerplate
smoothdeveloper 1 days ago [-]
In C#, you can't use the await keyword in a non async method, so I find the argument short sighted.
jayd16 1 days ago [-]
If your code base is already using async await it's really not an issue.
int_19h 1 days ago [-]
The point is that it's not actually different from C#, especially once you consider that F# also has task{} blocks that give you a .NET Task directly.
shortrounddev2 1 days ago [-]
I don't see how that changes things. You'd have to async it all the way to the top but the syntax is still cleaner than F#. If you're using an Asp.Net controller you just declare the handler as async Task<IActionResult> and it's fine. Even program main methods can be async these days
malakai521 1 days ago [-]
The syntax is exactly the same. You have `var x = await` in C# and `let! x =` in F#
The controller handler is also the same. It will be marked with `async` keyword in C# and `task` CE in F#
shortrounddev2 1 days ago [-]
It's absolutely not exactly the same; let! is only available within a computation block. If you want to return some value from the computation block and return to Functional land without having to pause the thread you need to use a continuation, which C# has built in syntactic sugar for in async/await and F# does not.
sparkie 1 days ago [-]
`await` can only be used in an `async` function. How is that so different from `let!` only being available in a computation expression?
shortrounddev2 1 days ago [-]
because an async function doesn't require you to change syntaxes to get them to work
Smaug123 1 days ago [-]
It's actually sort of the other way round. C# has hardcoded syntax for async/await. F#'s syntax for async/await is a fully-general user-accessible mechanism.
sparkie 12 hours ago [-]
They're not so different in that regard. C# `await` can be adapted by making an awaitable and awaiter type[1], which isn't to dissimilar to how a computation expression in F# needs to implement methods `Bind`, `Return`, `Yield`, etc.
In both languages these patterns make up for the absence of typeclasses to express things like a functor, applicative, monad, comonad, etc.
A computation block is the equivatent of an async function;
neonsunset 1 days ago [-]
As sibling comment pointed out, it's just .fsproj manifest and Program.fs file. What boilerplate do you speak of? It's on the opposite end boilerplate-wise to projects made in e.g. Java or TypeScript.
For 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)
twodave 1 days ago [-]
I suspect they were either referring to pre-.NET Core days before the new project formats came out or they're creating projects in Visual Studio and checking all the optional boxes. There indeed did used to be a lot more required boilerplate to get some code running. Now you can run a .NET project quite nicely in VS Code with 2 total files.
shortrounddev2 1 days ago [-]
Well also if you're using Visual Studio it will generate solution files as well, not just fsproj. I grew up doing C/C++ so boilerplate project/IDE/make files as well as build objects are something I expect to see. I think people who work in primarily JIT'd/interpreted languages are used to just having a directory tree full of source files and having some CLI tool manage everything for them. Maybe a dependency list file as well, but that's about it. Python is like this, and javascript CAN be like this
darksaints 1 days ago [-]
I'm completely convinced that F# (along with Scala, Haskell, and OCaml) adoption has stalled due to having ridiculously bad build systems. More significantly, they are being passed up in favor of Rust, which is a great language but nonetheless a bad fit for a lot of problem domains, simply because Rust has a superior build system. Hell, 80% of the reason I choose Rust over C++ for embedded work is because of the build system.
It baffles me that there are languages with non-profit foundations and are financially backed by multiple corporations which still have bad build systems. It is the most important investment you can make into a programming language.
ddellacosta 2 hours ago [-]
I don't really get this take, at least wrt Haskell--I know less about the others. I don't disagree that it's not ideal, but I still would compare the combination of nix+cabal in Haskell favorably with anything I've used in Python, JS, Ruby, Clojure...and other ecosystems I'm forgetting. Python and JS in particular I've always found absolutely miserable to work with when it comes to dealing with dependencies. So I don't believe that this is why folks aren't choosing Haskell (I think it has a lot more to do with how different it is from most people's programming language experience, and how so much of the documentation is aimed at non-beginners).
jadenPete 19 hours ago [-]
It’s always puzzled me that so many languages have their own build systems and package managers. Why aren’t programming language-agnostic build systems like Bazel and Buck more popular? It seems so strange that every new programming language essentially has to reinvent the wheel multiple times, inventing a new build system, package manager, formatter, linter, etc. I wonder if we’ll ever see something like LLVM for these technologies.
pjc50 6 hours ago [-]
Firstly a strong desire to self-host: write the build system in the language itself.
Secondly, often very differently shaped requirements. The dotnet SDK tries to keep its build specification (.csproj) files editable by Visual Studio, which is why most of the stuff in them is just XML properties.
You probably could build C#/F# with Bazel but that's not what Microsoft chose, and you kind of need to stay aligned with them and the large amount of MSBuild files in the SDK.
Rohansi 7 hours ago [-]
Because there are differences that go beyond just the language syntax. The build processes are very different for C++ vs. C#, vs. F#, etc.
C++: invoke compiler for all compilation units, invoke linker to combine object files into executable
C#: invoke compiler once with all source files listed
F#: same as C# AFAIK, except file order matters!
fodkodrasz 4 hours ago [-]
C++ I have worked only a little with it, more so with C, but AFAIK order of files does kind-of matter, so at least declarations need to be present in each file upfront before use.
C# has a multi-pass compiler so that it can compile and link the components from multiple files, without need of placeholder declarations, regardless of the order the symbols appear in the files.
F# has a single pass compiler, which keeps the compiler implementation simpler, but the file, and symbol definition order does matter that way. This is totally intentional, this is supposed to make the codebase more straightforward, with which I personally agree with. This avoids the need for declarations and centralization of them, the includes all the baggage that comes with that approach, and all the complexity C# has. I have rarely found a limiting factor, though there are some cases when it can be a bit inconvenient, for me the application setup/composition (~DI, but I prefer more static approach in F#) needed some cumbersome refactoring in some cases (have only vague memories by now, and yes, I know co-recursive types exists)
I really like F#, but rarely have to opportunity to work in it.
torginus 8 hours ago [-]
My two cents is that F# hasn't received the same care and attention as C# and working with it can be awkward.
At the same time, a lot of the cool features (list comprehension, pattern matching, immutable records) have slowly trickled into c#, giving even less incentive to switch
fodkodrasz 4 hours ago [-]
I personally find the way these features were shoehorned into the C# syntax an eyesore, I have quite some C# experience, and I think the language is getting more and more convoluted and noisy, with ever less coherent syntax.
On the other hand many of these features are really convenient and handy in F#. Adding many of the oh-my-gamedev-such-speed features from C# to F# also makes its syntax less pleasant to work with.
Personally I also think that the C# async model is terrible, and was a grave mistake. The F# async model with computation expressions, and explicit control over their execution context was a better approach, and I'm really sorry the hack-something-together to unblock the event loop WPF/frontend-dev usecase won over the more disciplined backend-focused approach.
n4r9 9 minutes ago [-]
I have the opposite experience. Being able to write stuff like this is refreshing:
public record Name(string First, string? Last = null);
public record Register(Name[] Members);
...
var register = new Register([new("John", "Doe"), new("Neo")])
It probably depends on what you're writing. I'm not using async much at all so I don't feel the pain of it.
germandiago 6 hours ago [-]
I use C++ with Meson and Conan and I can say that there is an initial learning curve if you need to adapt Conan recipes but once you get past, the results are quite good.
Lyngbakr 23 hours ago [-]
While I've never used it in anger, I really quite like dune. Was there something specific that makes you characterise it as "ridiculously bad"?
noahbp 19 hours ago [-]
Not Dune exactly, but having to run 'eval $(opam env)' in the terminal every time you open an OCaml project rather than the default being npm-like, where you can just open the directory and use the package manager command without having to think about it.
anentropic 9 hours ago [-]
(writing all the below while being aware you likely know much more about OCaml than I do...!)
Possibly `eval $(opam env)` is something that should just go in your ~/.zshrc
The OCaml folks have done some work recently to improve the onboarding documentation, which I think is going in a positive direction
> Local switches are automatically selected based on the current working directory.
johnisgood 7 hours ago [-]
The only issues I've had with OCaml's build system is using "ocamlopt", "ocamlbuild", "ocamlfind" manually, but this was solved by OASIS and now Dune. I don't need to think about it. It automatically compiles when I save the file in Emacs. Very easy to set it up (one time setup).
DeathArrow 11 hours ago [-]
I would call .NET build system excellent.
fodkodrasz 4 hours ago [-]
Lets settle on a finally good enough. I can give honest compliments on learning from the past problems and from the better examples in the indsutry.
You may not remember the early .net core times with yeoman and other then-current javascript ecosystem originated things applied in really cumbersome, half-assed ways, with lacking docs and always being in flux for years. The project.json era was terrible.
Also msbuild was way worse 10-15 years ago...
Mono with automake was special circle of hell IMO, I have very small exposure but it was really unproductive and painful.
jayd16 3 hours ago [-]
Whats pretty interesting is how outdated opinions of .NET are so sticky. Are we talking about what javascript was like 10-15 years ago?
I guess Microsoft could really make some headway if they got more folks to try it today.
throwaway2037 11 hours ago [-]
> I'm completely convinced that F# (along with Scala, Haskell, and OCaml) adoption has stalled due to having ridiculously bad build systems.
Scala? I am not trolling here: Are you joking? Scala is part of the Java ecosystem. Sure, Maven gets lots of hate on HN, but it is very mature and has excellent integration with IDEs and CI/CD systems (TeamCity, Jenkins, etc.). In the last 10 years, many Java developers have moved to Gradle, which has equally good integration.
> Hell, 80% of the reason I choose Rust over C++ for embedded work is because of the build system.
What is wrong with CMake for C++?
dkarl 4 hours ago [-]
Perl is mature, too.
Maven is awful. SBT is awful. Gradle is awful. I've used them all professionally, and the best I can say about them is that you can get the job done with them.
Newer languages and newer build systems are much better experiences, because of decades more hindsight and because language designers think about tooling from the start. Java was designed with the assumption that all software projects were built with Make, and with no ambition to improve on that. There was no Java-specific build tool until Ant was released as a standalone tool circa 2000.
> What is wrong with CMake for C++?
Granted, most of what's wrong with CMake is the problem it solves. Probably there's no solution that wouldn't be at least close to as awful as CMake. But it is objectively a hideous experience compared to any language created in the last 15 years.
oblio 10 hours ago [-]
How long are Scala compilation times for a Hello World CLI, a Hello World basic webapp and for a reasonably sized production size code base?
My guess is that it's much longer than for the equivalent Java apps.
> What is wrong with CMake for C++?
It doesn't manage dependencies.
oriolid 1 hours ago [-]
CMake has fetch_content, and CPM is a package manager built on top of it. They are not great.
pimbrouwers 1 days ago [-]
Our shop converted 6 years ago, from C# to exclusively F#. I also author and maintain some packages (falco, donald, validus and others). The language is tough to learn if you're coming from a C-style language. But worth the effort and experience. It's extremely concise a true delight to build programs in that are fast, robust and durable.
There are a few drawbacks, depending on your perspective:
- compilation is slower than c# and hot reload isn't supported (it's in progress)
- there are very few opportunities to use it professionally
- hiring devs can be challenging
Foofoobar12345 1 days ago [-]
Hiring devs is perfectly fine if you don't look for F# skills - just hire generally smart people, and allow them 1-2 weeks to get comfortable with F#. Make them just solve problems from project euler or something.
For those who have already done functional programming, they wont take more than 2 days to start getting productive. For those who have written a lot of code, it will take them ~2 weeks to pick up functional thinking.
Anyone who is still uncomfortable with F# after 1 month - well that's a strong signal that the dev isn't a fast learner.
Additionally, I've never had anyone reject our job offer because we do F#. I'm sure a whole bunch of people might only be looking for python or javascript jobs, but that's fine because I'm not looking for them. I always have more people who I want to hire but I can't due to budget constraints.
Source: direct experience - I run a pure F# company with a team size of ~80.
CharlieDigital 9 hours ago [-]
> Anyone who is still uncomfortable with F# after 1 month - well that's a strong signal that the dev isn't a fast learner.
I think you may be reading this wrong. Agree with sibling post that even teaching folks C# -- which isn't far off of TypeScript, Java, etc. -- is never so straightforward if the individual wants a full grasp of the tool.
For myself, I feel that I have "full" command of C# as a programming language, but also how to structure projects, how to isolate modules, how to decouple code, how to set up a build system from scratch for C#, how do deploy and scale applications built with C#, what the strengths and weaknesses are, etc. My definition of "comfort" would entail a broader understanding of not just the syntax, but of the runtime ecosystem in which that code operates.
GiorgioG 8 hours ago [-]
For me, my discomfort with F# is due to not knowing if what I’m doing is the correct/idiomatic way of doing things. With C# I have learned all the ways I should not do things…so it’s easier/faster to just use C#.
Kwpolska 4 hours ago [-]
The problem is, many recruiters don't work with this mindset. If they're hiring a Java developer, and they get a CV from someone who has 1 year of Java experience and 5 years of C# experience, they see 1 year of experience, and immediately put it on the "unqualified" pile.
pimbrouwers 21 hours ago [-]
Hi Isaac ;) Of course you can train people. But in my experience they take a lot longer to learn than you suggest.
z5h 1 days ago [-]
As a proficient Elm developer with industry experience, I’m wondering what are the biggest challenges in hiring devs? Is it the paradigm, learning the ecosystem, lack of interest?
Are you currently hiring?
Akronymus 1 days ago [-]
As someone who quite likes f#: It seems like a chicken and egg problem, not many companies doing f# because not many devs know it and not many devs learning it because not many companies are doing it.
I certainly wish I were doing f# professionally, but I only ever found 1 job listing for it, and that was in vienna while I am located like 200km away from it :(
Speaking of elm: I really like elmish for the frontend, when I need to make a dynamic page in the first place. Maybe that could be to your interest? (It transpiles to react under the hood via fable, which you can webpack into a drop in bundle. But I digress)
DeathArrow 9 hours ago [-]
Jobs are kind of rare. I have to learn F# hoping maybe I will find a job in one or two years. And if I find it, they might want someone with F# work experience.
cogman10 1 days ago [-]
How does the typing system work for F#?
From the article, it looks like it's mostly dynamically typed. Or is it inferred? Or is it something else?
Like, if I write
let hello value =
print value
hello "world"
hello 2
Does that just work?
To me, that'd be a point that might steer me away from the language. Deducible types seem vital to larger and long lived projects.
Nelkins 1 days ago [-]
It's statically typed and inferred.
With regards to your example, the print/printfn (equivalent of Write/WriteLine) functions are a bit funny in F#. They don't actually take bound string values directly. You need to specify the type (which could be a string, a number, obj, etc)
F# is a statically typed language with gradual typing and full type inference.
Given
let hello value =
printfn "%A" value
hello "world"
hello 2
The binding "hello" has "'a -> unit" signature where 'a is a generic argument it accepts because the "printfn" binding with a given format specifier is generalized the same way and an unconstrained 'T (here 'a) is the most narrow type inferred for "hello".
debugnik 7 hours ago [-]
> with gradual typing
Isn't gradual typing widely understood to mean "gradual between static and dynamic", which F# certainly isn't?
foretop_yardarm 20 hours ago [-]
Thanks for your work on falco, it’s a really great library.
DeathArrow 11 hours ago [-]
>- there are very few opportunities to use it professionally
My experience was that it was a surprisingly nice language with a surprisingly warty user experience: papercuts ranging from naming conventions and function call styles (`|> List.map` vs `.Select`), basic syntax (`foo.[0]` to lookup arrays), type system features (F# doesn't have covariance/contravariance even though C# does), IDE support (back then was only Visual Studio, whose support for F# was inferior to C#).
Ended up settling on Scala after that, as a language with its own Warts, but one that somehow managed to feel a more cohesive than F# did despite having largely the same featureset and positioning.
F# was my first functional language and one that changed how I look at programming, but at the same time I'm happy to not actually have to use it for serious programming!
munchler 1 days ago [-]
F# supports both functional and OO call styles. That's why you have both `|> List.map` and `.Select`. It can be a bit confusing at first, but the interoperability with C# is worth it.
Array lookup in modern F# is just `foo[0]`.
Subtyping is much less common in F# than in C#, so the need for covariance/contravariance is correspondingly lower. Personally, I've never needed it.
F# support in Visual Studio is now excellent. You can also develop F# in VS Code.
JohnyTex 1 days ago [-]
FWIW I think writing F# is a really cohesive experience in day-to-day work. While there are usually at least two ways to do things, due to .NET interoperability requirements, it’s usually pretty clear which way is the “right” way to do something.
F# feels kind of similar to Python in this regard, where there might be more than one way to do it, but there is community and ecosystem consensus on what is the right way.
I think a lot of credit should go to Don Syme for this; he seems to have a very clear vision of what F# should and should not be, and the combination of features ends up being very tasteful and well composed.
bozhidar 1 days ago [-]
I think these days F# is probably a big more polished than what you remember, so perhaps it's worth giving it another shot.
Being a hosted language always requires certain compromises (something that was also apparent in Scala). I used to do Scala professionally in its early days, but for me it felt it added just as much complexity as it addressed. I focused on Clojure back then (on the FP side at least), and I do think that F# probably brings more to the table than Scala. (if one is not constrained to Java, that is)
The tooling story is not great, but I've almost never seen great tooling for a language that's not super popular. I'm guessing what you get today with Rider is more or less as good as what VS has to offer.
djtango 1 days ago [-]
Interesting - I'm curious where your thoughts are now on using FP/Scala in 2025?
I've always looked at F# with envy as it is a hosted ML that will have extremely battle tested bindings to the important day to day stuff via C# (Darklang's stories of struggling with postgres and AWS when using OCaml was a good cautionary tale on the risks of using less common langs as a startup)
Never had a chance to try out Scala but am a seasoned Clojurian, as an outsider it seemed Scala suffered a little from being not opinionated enough so the ML family has been more appealing to tinker with even though Scala supports type classes out the box and will also have great ecosystem support via the JVM
hocuspocus 1 days ago [-]
It's never been a better time to try Scala if you're interested in the FP side. It's still very much "not opinionated" but the community and ecosystem have benefited from a certain convergence and given up on the "better Java" front which is served by Kotlin more adequately. Of course you can still consume any Java library when needed but it's best to avoid it if possible. Today you can pick between several ecosystems:
- Typelevel libraries: modern and more welcoming take on ScalaZ ideas, rich and mature, extensible libraries that are written in "tagless final" style.
- ZIO: concrete "super monad" with 3 type parameters, shuns the Haskell baggage and category theory lingo but pretty much the same concepts, compile-time autowiring dependency injection, a bit less mature.
- Kyo: new effects system on the block, pushing Scala 3's type system to the limit to stack effects using an "auto-flattening" monad (sorry if I butchered the description).
- Li Haoyi's own ecosystem that sticks to the standard library and JVM built-in mechanisms whenever possible, focused on Python style expressiveness, only more functional and with stronger types.
- I'd skip Akka/Pekko libraries but it's still an interesting piece of software if you need actor based, stateful cluster sharding.
Martin Odersky and the LAMP are focused on "capabilities" and we should eventually see something like direct-style algebraic effects, or like Kyo but without monads.
Also we have much better build systems than before (Scala-CLI, Mill, sbt has improved a lot too), binary backwards compatibility since Scala 3, and a very capable LSP backend if you don't like IntelliJ IDEA.
DeathArrow 11 hours ago [-]
So, there is a gazillion ways to do things and the community didn't settle on one? I don't find that very attractive when trying to learn a new language.
hocuspocus 4 hours ago [-]
The exact same can be said about Java or Kotlin.
tasuki 1 days ago [-]
Very good summary, thank you! I've mostly stopped writing Scala, but it's still close to my heart.
17 hours ago [-]
protonbob 8 hours ago [-]
I've found that as C# gains much of the features that F# has and will soon gain more (pattern matching, functions as first class data types, great fp libraries, etc) the "moat" that F# has over C# has gotten smaller. I write most of my c# code in a primarily functional style, but I still have the advantage of using the libraries in their own native ways that follow the examples given by microsoft and other vendors.
runevault 4 hours ago [-]
Watching c# eat f# features as someone who has dabbled in f# lightly for over a decade has been wild. And supposedly DU's are in the works but multiple years out.
Though one thing I doubt c# ever gets that I love when I'm writing f# is pipeline operators. I love the way they read, from object/collection being worked on and then a list of operations being run on it in order from left to right (or you can do right to left if you need to for some particular reason).
gdfsfs8895 3 hours ago [-]
[dead]
eknkc 1 days ago [-]
As far as I can tell F# is one of those things where every single user is extremely happy. This happens rarely and I really am curious about the thing but never had time to get into it. I'm also pretty well versed in the .net ecosystem so it's probably gonna be easy.
Any tips? What kind of workflows might benefit the most if I were to incorporate it (to learn..)?
pjc50 1 days ago [-]
The funny thing is that you can write very similar code in C#, so maybe you don't need to switch which language you're using as a CLR frontend.
using System.Linq;
using System;
var names = new string[] {"Peter", "Julia", "Xi" };
names.Select(name => $"Hello, {name}").ToList().ForEach(greeting => Console.WriteLine($"{greeting}! Enjoy your C#"));
LINQ is such a good library that I miss it in other languages. The Java stream equivalent just doesn't feel as fluent.
issafram 11 hours ago [-]
You're being way too nice. Java stream is nowhere near as easy to use as LINQ. I'd say that LINQ is easily one of the top 10 coding features that Microsoft has ever created.
DeathArrow 8 hours ago [-]
I think LINQ is inspired by SQL. You can do whatever you can with SQL, it's just that the data source might differ IEnumerable with some in memory data, IQueryable with some DB. Or you can use async enumerable and your data source can be whatever web API or protocol.
psychoslave 1 days ago [-]
As far as fluency goes, that’s not very impressive.
%w{Peter Julia Xi}.map{"Hello, #{it}"}.each{puts "#{it}! Enjoy your Ruby"}
That’s of course trivial examples. And while Ruby now have RBS and Sorbet, it’s yet another tradeoff compared to a syntax that has upfront static analysis as first class citizen in mind.
That is, each language will have its strong and weak points, but so far on "fluency" I’m not aware of anything that really beat Ruby far beyond as Ruby does compared to other mainstream programming languages.
int_19h 1 days ago [-]
Ruby is dynamically typed, which makes "fluent" API design that much easier at the cost of maintainability elsewhere. If you want to compare apples to apples, you need to compare F# to other statically typed languages.
psychoslave 11 hours ago [-]
Also note that the following is a valid Crystal-lang code:
%w[Peter Julia Xi].map { |name| "Hello, #{name}" }.each { |greeting| puts "#{greeting}! Enjoy your Crystal" }
As they put it:
>Crystal is a general-purpose, object-oriented programming language. With syntax inspired by Ruby, it's a compiled language with static type-checking.
But this time, one can probably say that Crystal will lake the benefits of ecosystem that only a large popular language enjoy.
I guess on that side F#, relying on .Net, is closer to Kotlin with Java ecosystem.
paddim8 7 hours ago [-]
The only difference is that you have to specify the type of the list when you declare it though... That's not really a big deal.
new List<string> { "Peter", "Julia", "Xi" }.Select(name => $"Hello, {name}").ForEach(greeting => Console.WriteLine($"{greeting}! Enjoy your C#"))
psychoslave 4 hours ago [-]
Nothing is that much a big deal on a small selected sample, on the one hand on the other. That is, maybe some will prefer mandatory explicit type for every single variable, and some other will prefer type inference whenever possible, and both have pros and cons.
To jump in a REPL (or any debug breakpoint observation facility), having optional type inference is a great plus to my mind.
Note that Crystal does allow to make type explicit, and keep the fluent interface on track doing so:
Array(String).new.push("Peter", "Julia", "Xi").map{|name| "Hello, #{name}"}.each{|greeting| puts "#{greeting}! Enjoy your Crystal"}
Let’s remark by the way that, like with C# lambda parameters, block parameters are not explicitly typed in that case.
psychoslave 24 hours ago [-]
That's exactly what I meant with the two last paragraphs.
bob1029 1 days ago [-]
You can write a vast majority of your C# codebase in a functional style if you prefer to.
All the good stuff has been pirated from F# land by now: First-class functions, pattern matching, expression-bodied members, async functional composition, records, immutable collections, optional types, etc.
int_19h 1 days ago [-]
I wouldn't say "all" - C# doesn't have discriminated unions yet, which is kind of a big one, especially when you're also looking at pattern matching. A
A language is just as much about what it can't do, then what it can do.
bob1029 1 days ago [-]
Can you elaborate on what you mean by this?
I assume you are implying that too many choices could confuse a junior developer, which I agree with. However, I don't think this is a concern in the bigger picture when talking about the space of all languages.
UK-Al05 10 hours ago [-]
A language by making certain things harder makes the resulting code be built in a certain way.
F# makes mutable code harder to do, so you tend to write immutable code by default.
gonesurfing 24 hours ago [-]
My 2p's worth is that the whole of F# is more than the some of its parts. When you say in your previous comment "All the good stuff has been pirated from F#" it misses the point of what it's actually like to use F#. The problem is, it's almost impossible to communicate what it's like. You have to try it and you have to keep going until you get over the initial "WTF!?" hump. There will be a WTF hump.
For example, C# may have cribbed the language features, but F# is expression based and immutable by default. Try using the same features in this context and the whole game changes.
guhidalg 1 days ago [-]
I don't know if there's a name for it but essentially F# is where the language designers can push the boundaries and try extremely new things that 99% of users will not want or need, but eventually some of them are such good ideas that they feed back into C#.
Maybe that's just research, and I'm glad that Microsoft hasn't killed F# (I do work there, but I don't write F# at work.)
debugnik 1 days ago [-]
> F# is where the language designers can push the boundaries
It really isn't, not anymore. F# now evolves conservatively, just trying to remove warts and keep up with C# interop.
And even then some C# features were considered too complex/powerful to implement (e.g. variance, scoped refs) or implemented in weaker, incompatible ways when C#'s design is considered messy (e.g. F#'s non-nullable constraints disallow value-types, which breaks for some generic methods written in C#, sadly even part of the System libs).
klysm 1 days ago [-]
This isn’t a great example of what linq is good at. There’s no reason to do ToList there, and the ForEach isn’t particularly idiomatic
pjc50 1 days ago [-]
Yeah, I hit the problem that there isn't a null-type equivalent of Select() for Action<T>, nor is there a IEnumerable.ForEach (controversial), so that's a bit of a hack. But I wanted to make it as close to the original example as possible.
bob1029 1 days ago [-]
> There’s no reason to do ToList there
In this case, I would move it to the very end if we are concerned about the underlying data shifting when the collection is actually enumerated.
Forgetting to materialize LINQ results can cause a lot of trouble, oftentimes in ways that happily evade detection while a debugger is attached.
klysm 1 days ago [-]
> if we are concerned about the underlying data shifting when the collection is actually enumerated
I’m not sure what you mean by this. You can fulfill the IEnumerable contract without allowing multiple enumerations, but that doesn’t really have to do with the data shifting around. Doing ToList can be an expensive and unnecessary allocation
bob1029 1 days ago [-]
Imagine a live SQL query you are subsequently filtering with LINQ.
DeathArrow 8 hours ago [-]
Yes, ForEach isn't idiomatic but he could use Select instead.
kkukshtel 1 days ago [-]
Modern C# collection expressions make the definition of names closer to F#:
string[] names = ["Peter", "Julia", "Xi"];
I know working on "natural type" of collections is something the C# team is working on, so it feels possible in the future that you'll be able to do this:
<source>(5,1): error CS9176: There is no target type for the collection expression.
.. which I took to mean that, because .Select is an extension method on IEnumerable, the engine was unable to infer whether the collection should be a list, array, or some other type of collection.
It seems reasonable to have it default to Array if it's ambiguous, maybe there's a downside I'm not aware of.
DeathArrow 8 hours ago [-]
Maybe you can submit a proposal/issue to the C# language team? I'd vote for it!
voidUpdate 1 days ago [-]
I love LINQ, maybe a little too much. I can end up writing monster oneliners to manipulate data in just the right way. I love list comprehensions in python too, since they can work in similar ways
EVa5I7bHFq9mnYK 14 hours ago [-]
That could be shortened to
names.ForEach(name=>Console.WriteLine($"Hello, {name}! Enjoy your C#"));
gibibit 1 days ago [-]
For reference, Rust provides a similar experience
let names = ["Peter", "Julia", "Xi"];
names
.map(|name| format!("Hello, {name}"))
.iter()
.for_each(|greeting| println!("{greeting}! Enjoy your Rust"));
munchler 1 days ago [-]
F# shines on the back end, where its functional-first style is very adept at crunching data. Think about data flows in your system: Any place where you use LINQ in C# today to select/filter/transform data might be even better in F#. Parsing is also a great F# use case (e.g. parser combinators), although a fairly narrow niche.
JohnyTex 1 days ago [-]
Personally I think F# is excellent for writing ye olde CRUD applications, especially as the business logic becomes more complex. F# is really good at domain modeling, as creating types comes with minimal overhead. C# has improved a lot in this area (eg record types) but it’s still got a long way to go.
Thank you, for someone interested in using F#, that is great.
I see you use Giraffe but I wonder how hard would it be to use Web API or to mix F# projects with C# projects in the same solution.
piokoch 1 days ago [-]
"As far as I can tell F# is one of those things where every single user is extremely happy" Isn't it because language has rather small community of passionate people, who are devoted to their language of choice?
F# popularity is somewhere between CHILL, Clipper and Raku langs, that are probably as obscure as F# for typical software dev.
int_19h 1 days ago [-]
I'm pretty sure that there's more production code written in F# than in all those other three combined.
psychoslave 1 days ago [-]
I know Raku from Perl fame, and F# because it’s Microsoft, but CHILL and Clipper are totally new to me, so in my own humble experience these two latter look far more obscure. :D
orthoxerox 23 hours ago [-]
Clipper is old. It's dBase/xBase/FoxPro, pre-SQL DBMSs.
DeathArrow 7 hours ago [-]
If we consider number of jobs, it's probably on par with Rust.
reverseblade2 1 days ago [-]
Here's a Saas that actually makes money written fully in F#
F# is beautiful, but I could never crack the nut and get fluent in it. I think the big problem is I only know a little C#, so it is difficult to figure out the object oriented methods that F# depends on. It was the same thing with Clojure and Scala for the JVM. I have zero interest in first learning C# or Java, just to use those platforms.
diggan 1 days ago [-]
> It was the same thing with Clojure and Scala for the JVM. I have zero interest in first learning C# or Java, just to use those platforms.
FWIW, I managed to learn Clojure without knowing anything from Java/JVM before diving into it. I did have plenty of JS experience which made ClojureScript easier to pick up I suppose, but Java works more or less the same as every other Algol-like and/or OOP language out there so if you have any previous experience with something like that, basic Java is trivial to pick up even accidentally.
netdevphoenix 1 days ago [-]
you are not supposed to do oop in f#
7thaccount 1 days ago [-]
I'm aware, but you need to understand the .NET ecosystem to get anything practical done (at least when I was using it in 2017). All the books written on it (I own 3) are also the same way and assume you're a skilled C# dev.
miloandmilk 1 days ago [-]
100% this, I spent many months going through the most recent books on F# including one which the latest version was only released last year I think.
They all seem to try and shield you from the fact that you are much better placed if coming from C# (which everyone seems to refer to as .net these days) and have a solid understanding of the .net class library.
All the main web frameworks sit on top of asp.net and pretty much all official documentation for that is in c#
Such a shame because I learnt so much about types from trying to crack f# for real world application. fsharpforfunandprofit taught me heaps which I apply to other languages, but I don't want to become a c# developer which comes with all the years of changing best practices to be able to really be productive in f#.
Sorry if I am coming across as bitter but I just can't see learning f# in isolation from c# which is an absolute shame.
neonsunset 1 days ago [-]
What is the issue with learning C# alongside it, if only the bits necessary to improve the F# experience? Both are excellent languages.
miloandmilk 1 days ago [-]
They are both excellent languages, I just literally don't have the time to commit to do that at the moment.
I think if I ever have time for another go I would learn enough to be proficient in c# before diving back in.
hajile 1 days ago [-]
F# depends heavily on existing C# libraries and those are all OOP.
smoothdeveloper 1 days ago [-]
One way to look at it, but consuming OOP libraries doesn't turn code into OOP.
Also, FSharp.Core (which most F# code leans heavily on) is not OOP at all.
F# promotes object programming, doesn't proscribe mutability, encourages function and data approach.
It offers simple access to the different paradigms, with some opinionated choices (e.g. preventing leaning on OOP beyond an arbitrary stretch, like no "protected", only explicit interface implementation, etc.).
genter 1 days ago [-]
Except that there's a huge number of libraries written in C# that are available to F# (since both run on the CLR), and you have to do OOP in F# to use them.
shortrounddev2 1 days ago [-]
FP and classes are not mutually exclusive
ninalanyon 1 days ago [-]
Why not? It does it very well, better than C# in my opinion. At least that was the case ten years ago when I last used C# and played with F#.
zem 1 days ago [-]
oop is just another tool in your toolbox; if f# provides it and it's the best way to express a given algorithm you should definitely go ahead and use it. oop got a bad name due to people trying to shoehorn it into places it was not the best way to express something, and it seems like you're making the inverse mistake here.
jonsagara 1 days ago [-]
The killer feature for me is type providers. I need to read a lot of CSV files of varying formats, and the CSV Type Provider lets me make quick work of them in a type-safe manner.
Agreed. Type providers bring metaprogramming to F# in a way that’s both powerful and innovative. The concept is amazing, enabling a new frontier for dynamically extending type safety. My only surprise is how little fanfare it has received since its introduction.
For a more pragmatic take on static metaprogramming, the manifold project[1] for Java is worth a look. Unlike F#, which leans toward expansive schemas, Manifold focuses on contained, compile-time integrations—handling JSON, XML, SQL, GraphQL, and even other languages in a seamless, type-safe way.
Why would Lispers feel at home with its (whitespace delimited) syntax? Quite the strange claim.
I know this isn't a common rant, but I hate so-called functional language still bowing to the "infix mathematical operator special case" dogma, when those are just binary (variadic in Lisp) functions.
Always found it pretty appealing, otherwise. And no ";;"!
110bpm 23 hours ago [-]
I put together a quick-start guide to F# Computation Expressions — showing how you can go from C# async/await all the way to Result<> workflows with let!... and!... expressions, and even a custom validation {} CE. [0]
This is a practical side of F# that doesn’t get enough spotlight — but one I’m using daily.
> Trivia: F# is the language that made the pipeline operator (|>) popular.
I’m not a dabbler in exotic languages, so this definition of “popular” was puzzling. I’ve literally never seen that operator before. Maybe I need to get out more.
sdsd 2 hours ago [-]
I've used it in Racket, which is not exactly "popular" but common in universities as a teaching language. I actually built a fairly popular Tor hidden search engine in Racket nearly a decade ago, but I quickly shut it down when I ran some stats on the most common queries.
zdragnar 1 days ago [-]
It exists in several similar languages such as elixir, and was even a proposal for ecmascript, but never really got traction.
sundarurfriend 1 days ago [-]
I'm familiar with it via Julia, and I believe recent versions of R also have it.
It has been "stuck" at Stage 2 for a while, though.
shermantanktop 1 days ago [-]
Thanks for that link! Now I want pipe operators...
hurril 1 days ago [-]
F# is a wonderful language, one that I write as my daily for the second time during my carrier. It _baffles_ me how it isn't more popular than it is because it truly is very very good. And I say this as an experienced and avid functional programmer.
We even do the frontend in it using Fable and Elmish, which is to say: we basically write our frontends in Elm, but the platform is .NET.
protonbob 1 days ago [-]
> which is quite odd for what is supposed to be the flagship editor for F#
The flagship editor is Visual Studio, not vs code.
MaxGripe 1 days ago [-]
The flagship editor is Rider
bozhidar 1 days ago [-]
But it's Windows-only, so it's not an option for me.
GiorgioG 1 days ago [-]
Rider is an option for you. Community edition is free too.
LandR 11 hours ago [-]
Rider is now entirely free for non commercial use.
protonbob 1 days ago [-]
Who said it was? It is the flagship editor though.
neonsunset 7 hours ago [-]
Why not VS Code with Ionide? It’s quite nice.
nickpeterson 1 days ago [-]
Because it’s great, and people that think otherwise are dead to me.
MrMcCall 1 days ago [-]
Curried functions combined with that magnificent pipe operator, overlaid on the .NET runtime. Don Syme et al knocked it out of the park.
It's the one programming language that changed how I think about programming.
I'm only talking about the version before type providers. Then it got messy.
Before that, we could (and I did) recompile fsi.exe to do some custom prompt manipulation. It was a slog, but it worked, but then Microsoft faded from my life. Still, that early version (I believe 2.0) F# is just magnificent.
munchler 1 days ago [-]
F# is up to version 9 now, and has only improved over time, IMHO. Type providers are a very small part of the story and can be avoided entirely if you want.
jasonthorsness 1 days ago [-]
I tried F# when it was first released and was not a fan, but it sounds like that impression is a little outdated. C# has come so far in that time it’s almost a new language. I’ll have to take another look.
MrMcCall 1 days ago [-]
I don't know what C# has for an interactive prompt nowadays, but F#'s commandline environment, via its fsi.exe, was a revelation back then. It prevented having to have entire solutions to contain test projects to explore different areas of the vast .NET framework, especially when just learning how to use specific methods or objects.
DeathArrow 7 hours ago [-]
For C# you can use LINQpad, a .NET scratchpad. You can even mix and match F# in it.
speed_spread 1 days ago [-]
Why would type providers be avoided? It seemed to me like a nice metaprogramming feature, akin to what Zig does with comptime types (except runtime?)
Smaug123 1 days ago [-]
Yeah, they're terrifying. It's often not that hard to generate the code (e.g. https://github.com/Smaug123/WoofWare.Myriad/ is where I pump out these things) for a bunch of what you would want to do with a type provider, and that's much less existentially terrifying if it's possible.
munchler 1 days ago [-]
Type providers are very powerful but involve running arbitrary external software at compile-time (e.g. a SQL Server or Postgres database). This can be difficult to set up and configure reliably in a multi-person project.
owlstuffing 3 hours ago [-]
You're not entirely wrong, but when it comes to SQL, the trade-offs are unavoidable. You either embrace a conventional, not-SQL approach with all its limitations, or you treat the database as the single source of truth (SSoT). Both have downsides, but configuring a designated local or shared database for this purpose is no less reliable than conventional approaches.
As for type providers in general, I don't think databases are the best example of their typical use case. Most type providers don’t interact with external systems; they usually parse schemas, configuration files, or other structured data to generate strongly typed representations. The database-backed approach is just one variant, not the norm.
Akronymus 1 days ago [-]
Type providers can be extremely brittle IME. Altough, I guess if it is referring to version controlled example data that probably works better than referring to a DB or something like that directly that the dev has to provide.
MrMcCall 1 days ago [-]
For me, I already had all the featues I needed.
Plus, I'm not going to be downloading, configuring, or running any separate code at runtime. The project is the project, it's going to process some files, communicate with some services, and communicate with the UI, if any.
If I need to consume a service, it should be defined such that I manifest the interface module (perhaps via WCF) and then connect to it progressively from stub to ever greater functionality in test to final implementation. Trying to write a program to do all that at runtime is not sensible, IMO.
Metaprogramming via reflection, however, was useful for exploring the vast .NET framework, and I used those to great effect, especially in exploring .NET's various UI frameworks (WinForms and Silverlight), but never to create code at runtime via the emit functionality. No, that's my job: to emit code that is tested and works and is comprehensible.
MrMcCall 1 days ago [-]
I don't doubt it, but I don't run Microsoft software any more. I've seen enough embrace, extend, and extinguish in my lifetime to not depend on them for my code's execution environment.
My current work needs nothing the .NET environment provides that I can't use python's standard libraries to get done, or bash and C if I need to.
But I'm lucky to no longer be in a corporate environment, so I don't need to consume commercial services, which was much easier using WCF within .NET. Back in my previous life, constructing n-tiered services on top of SqlServer using WCF was slick, indeed.
To any who are interested in how to construct such n-tiered applications simply but securely and precisely, I highly suggest Juval Lowy's IDesign system. He had three specific videos that I watched three or four times each until I understood his distillation of his vast expertise. Of course, Mr. Lowy is one of the co-designers of WCF, which was an excellent bit of tech.
munchler 1 days ago [-]
FWIW, F# is an open source project controlled by the F# Software Foundation, the .NET Foundation, and Microsoft.
MrMcCall 1 days ago [-]
> controlled by the F# Software Foundation, the .NET Foundation, and Microsoft.
It is controlled by Microsoft. It's not going on my Linux or BSD boxes.
I know how they work, and I want nothing to do with them.
lunarlull 23 hours ago [-]
Do you make sure to run a linux kernel with all the MS stuff patched out also?
MrMcCall 17 hours ago [-]
No, but if it came in the standard install there's nothing I can do about it save spending hours and hours auditing my install. I don't do that kind of thing nowadays.
Separately installed software? Not a bit of it.
akkad33 1 days ago [-]
It has great ideas but because of all these conveniences it is very bad for performance based programming making it slower than C#. I like the ideas in Roc language to make functional programming as fast as imperative by controlling allocations in things like closures
MrMcCall 11 hours ago [-]
That's interesting. Thanks for the heads-up.
1 days ago [-]
turtlebits 1 days ago [-]
It might be great, but IME, MSFT docs and tooling are subpar, and anything dotnet related is/was a disaster.
GiorgioG 1 days ago [-]
As a 20+ year C# developer I’ve tried several times to learn/use F#. Despite being interested in FP, my brain is having trouble figuring out how to structure my code in F#. In C# I’d either build a service (or use the mediator pattern) for the domain and a repository for data access. With F# it’s functions all the way down and it feels unnatural (as silly as that may sound).
Akronymus 1 days ago [-]
along with what jcmontx said: F# is structured bottom from top. As in you can't reference something that is later defined earlier. I find that naturally leads to getting a decent enough structure "for free" because it forces you to have your basic functionality early on and build on that later.
That also, IMO, makes untangling/splitting up parts of the codebase easier as well.
jcmontx 1 days ago [-]
The secret is currying. Replace your DI for currying and you'll start to see somewhat similar patterns
Have you tried using a book or a tutorial to see how things can be done using idiomatic F#?
MrMcCall 22 hours ago [-]
That makes sense when one is used to the Visual Studio organization of solutions and projects, with some main method somewhere being the entry point, unless it's a WCF service or somesuch that gets run via a service manager.
I only used F# at its command line, fsi.exe, to give me commandline access to .NET for exploration, testing, and munging data. Over time, I built up quite a library of usable functions that I'd have the fsi.exe program pre-load when I kicked it off, leaving me at the prompt with all .NET namespaces and my code ready and accessible.
Once you get access to your database's data, it's easy to write queries against it and then play with the data. I could then port the F# processing bits that worked into my C# projects as necessary, but it was far easier to do it that way than to write the logic deep within complex multi-project solution files, where the various classes are spread throughout the projects' files.
I also just really enjoyed using F#.
mesic 8 hours ago [-]
F# is getting some traction in Norway. I know for a fact that places such as NRK (BBC eqvivalent), Resoptima, Frende Forsikring and my current employer, REN are all using F#.
I'm waiting for the excellent F# Article about railroad-coding to be posted here.
Required F#e reading :) No not trolling. Am on mobile and traveling else I would have searched-posted
Two nice things about F# are that you can introduce it into an organisation using the dotnet ecosystem and that you can use all libraries in dotnet, which is a huge advantage over OCaml.
Otherwise, I am happy with OCaml, but F# has also a place in this world.
UlisesAC4 13 hours ago [-]
You can use adapters via Foreign Function Interface and interact with C++ code. The deal breaker is that memory is separated, C++ code has its own heap and Ocaml too. Quiet different to F# in which operating with C# is seamless and the runtime is the same.
DeathArrow 7 hours ago [-]
You can call C++ code from F#, too.
justanotheratom 1 days ago [-]
F# was my favorite language, but
- You have to chose the language of the Domain that you are working in, e.g, Swift for native iOS Development. Supabase Backend requires TypeScript, etc.
- LLMs don't care about F#.
aaronmu 1 days ago [-]
I've been using F# professionally for the past seven years across different contexts. First in a small software shop and now while bootstrapping a SaaS company. Some observations:
* It’s easier to attract smart developers to an F# project than to a [mainstream language] project. This was one of my driving beliefs when I introduced F# seven years ago. https://www.paulgraham.com/pypar.html. This is probably just as true for languages like Elixir, Clojure, ... But F# is what we went with.
Small Software Shop Context
* We operated in a small market where customers eventually dictated our tech stack (.NET & React). In that market, F# was a major advantage—it allowed junior developers to build apps that "just worked" with minimal regressions. Even with mediocre code quality, I felt confident that we could refactor safely at any time.
* I constantly had to justify F# to clients, which was exhausting. We always delivered decent results, so it worked out, but my partners were never as confident in defending F#.
Bootstrapping a SaaS Company
* F# has been invaluable for shipping features quickly and taking shortcuts when needed.
* Three years in, our codebase is large and contains its fair share of messy parts. But we can still develop new features at high speed with minimal regressions. Refactoring is relatively safe and straightforward.
* Compilation speed is the Achilles’ heel. If you don’t monitor it, the compiler slows down to the point where it impacts productivity. Earlier this year, waiting over a minute for feedback after a small change became unbearable. A lot of our "clean-up" work focuses on optimizing compilation times. We're still learning, but we’re optimistic that we can restructure the project to significantly improve build performance.
EDIT: maybe one more point. I see a lot of C# vs F# popping up here. Yes, C# has all the features that F# has. But do not underestimate how well designed F# is. It is an extremely simple language to learn compared to C#. There is a very limited amount of keywords to learn. And they compose extremely well. If you learned F# 7 years ago, took a break, and came back today, you'd simply write the same boring code that you would have written 7 years ago. And along the way you'd find out that some things have gotten a bit nicer over time.
nickpeterson 1 days ago [-]
I’ll add that features isn’t really a constructive way to think about the differences between C# and F#. C# has more ‘features’ than most other programming languages. One of the core features of F# is less features and churn. Also, I really appreciate the way F# maintainers agonize over how to maintain the language and keep it coherent. You don’t get the feel they’re chasing features at all.
GiorgioG 1 days ago [-]
As a 20+ year C# dev...where do I learn how to structure apps in F#? In C# my ASP.NET Controller might use a service (or a mediator) to execute some domain logic and that in turn will use a repository pattern (or EF DbContext) to update/query a database. How are dependencies injected in? It seems like there are multiple ways of going about it, but I don't have enough knowledge of F# to know 'the proper way' to do it.
FWIW you can do it exactly the same way you do it in C#; it’s not “wrong”, it might just feel a bit out of place.
systems 1 days ago [-]
The problem with F#, Clojure and Elixir (hosted languages)
For F# , you need some basic C# knowledge
For Clojure, you need some basic Java knowledge
For Elixir, you need some basic Erlang knowledge
I like all 3 languages but usually each vm have a primary language, and each hosted language eventually become hosted on that primary language not the vm
I understand that for many task simple, to medium complexity, you might not need that, but it seem as you try to be more advanced you hit the wall of having to learn you host vm primary language
skrebbel 1 days ago [-]
> For Elixir, you need some basic Erlang knowledge
As an Elixir programmer, this does not resonate. Basically the only thing I've ever felt I needed to understand Erlang for was ets, but let's be honest, that's not really proper Erlang but just the terrible ets query syntax. And all this requires is "ability to read enough erlang term syntax to be able to understand the ets manual". I don't think I could write a single line of correct Erlang by heart.
I feel like that's different in F#, where you still need to know lots of .NET internals which are all documented in C#y terms with C# examples etc. Elixir wraps pretty much all good Erlang/OTP internals in nice Elixiry modules, which solves that quite nicely.
Elixir has its warts but this really isn't one of them.
graemep 1 days ago [-]
Thanks. I know a bit of Erlang (put some effort into learning, but never used it in real life, probably forgotten what I learned) and want to learn Elixir which seems better suited to what I want to do in the short to medium term.
iLemming 5 hours ago [-]
> For F# , you need some basic C# knowledge For Clojure, you need some basic Java knowledge For Elixir, you need some basic Erlang
Honestly, none of this really rings a bell. Having used all three options, I never felt that. Well, I already knew C# before getting into F#, but honestly, it felt like my C# knowledge at the time was more of a distraction. Been using Clojure for nine years, never done any serious Java and have not felt any need for it. Not knowing Erlang wasn't a problem with Elixir, like at all.
LandR 11 hours ago [-]
I've written a lot of Clojure now, and I've managed to avoided learning any Java really.
chamomeal 6 hours ago [-]
That’s a reassuring thing to hear as a new clojure learner who has little interest in java.
What bits of java have you ended up needing? Like do you often use java libraries that don’t have clojure wrappers?
I feel like I’m often running up against little things. I’ll google “how to do xyz in clojure” and the top SO answer is to use a java library that apparently everybody already knows about, cause so many clojurists came from java first!
iLemming 5 hours ago [-]
> What bits of java have you ended up needing?
The same with Clojurescript and JS (and probably with Clojure-Dart) - you have nice interop with the hosting platform. The need for learning anything about Java (while writing Clojure) basically boils down to finding API documentation for a specific class and simply using it. That's all. That's all you'd ever need.
graemep 1 days ago [-]
Erlang is not a difficult language. Unusual, but actually quite sane syntax. If you are already familiar with Elixir it would probably be pretty easy to learn the basics of Erlang.
innocentoldguy 1 days ago [-]
I worked with Elixir for over five years without knowing anything about Erlang. I know Erlang now, but only because I was interested in learning it, not because I needed to do so to write Elixir code.
lysecret 1 days ago [-]
I worked a lot in F# and loved it. I love that it has a lot of great functional ideas without being too pedantic about being 100% functional all the time. (You can have mutating state or just call arbitrary C#.) I took a lot of its insights into my daily python code too. I especially love match.
mrkeen 1 days ago [-]
There's no need to be functional 100% of the time, and it's not pedantry.
You mark your functions and non-functions as such, so the compiler can get your back.
phplovesong 1 days ago [-]
Last time i tried F# i got bit by the weird concurrency story. There was async/task and somwhow they did not play well together. Also the dev tooling (for vim) was subpar, compared to ocaml (lsp). Compile times also was on the slower side.
110bpm 1 days ago [-]
`async` is F#'s original implementation of async programming. It is the precursor to C#'s await/async.
`task` targets the .NET TPL instead, which is also what C#'s await/async and all of .NET *Async methods use.
While the `async` implementation still offers some benefits over `task` (cold vs. hot starts [0]), my advice is - if you're doing backend code on .NET, you should use task. The tigher integration with the .NET ecosystem & runtime results in better exception stack traces, easier debugging and faster performance.
If you use task { } CE's you will get really good UX (it is recommended to use them over async CE's). They were introduced in F# 6.0 to address outstanding interoperability issues. As of now, writing asynchronous code is more convenient than C# (which is more convenient than Go or other languages which are less expressive w.r.t. writing highly concurrent code).
aloisdg 1 days ago [-]
F# is corporate friendly ML. Love it.
gwbas1c 1 days ago [-]
If you've had C# and F# co-exist in the same codebase, how do they co-exist? Is it like C# and VB.Net where a project (dll) is either C# or VB.Net, and they can reference each other?
Or: Is it more like the Swift / Objective C ecosystem where Swift, Objective C, and even straight C can co-exist in the same library?
In a mixed C# and F# codebase, generally when do you favor C# versus F#?
Coming from a C# background, what are the areas where F# is a better language?
Any success stories for F#, especially if it co-exists with C#? Any horror stories?
debugnik 1 days ago [-]
Yes mixing is just like with VB.NET.
When mixing, you often write business logic as self-contained F# libraries with a C#-friendly API; and use C# to integrate them with whatever imperative, reflection-heavy and DI-heavy frameworks .NET is promoting the current year, since those are filled with interop edge cases for F# anyway.
You really want to avoid a language sandwich though (e.g. C#/F#/C#), because you'll keep wishing to remove the middle layer. Sadly, the addition of source generators make this mistake even more appealing.
neonsunset 1 days ago [-]
You have likely heard "functional core, imperative shell". This refers to having IO-heavy code that favors imperative patterns be written in C# and then have the actual domain logic core written in F# which is much better at expressing it. Because both languages are hosted on .NET, you simply achieve it by having two projects and having one reference another. It is very seamless F# and C# types are visible to each other if marked to be so.
The biggest advantage of F# is its gradual typing and full type inference which allows to massively reduce the amount of text required to describe application or domain logic. It is also extremely composable and I find doing async in F# somewhat nicer than in C# too. F# also has better nullability (or, rather, lack of thereof) assurances and, in my opinion, better UX for records.
gwbas1c 1 days ago [-]
That's just like how C# and VB.Net can co-exist in the same project. Would you pick the pattern of:
1: C# Library with interfaces and/or abstract base classes
2: F# library with implementations of those interfaces and base classes
3: C# program (console, web service, GUI, ect) that specifies the implementations in Dependency Injection
Or is there a simpler way for C# and F# to co-exist in the same project (dll or exe)?
int_19h 1 days ago [-]
You don't really need to split 1 & 2, since F# can define .NET interfaces and abstract classes just fine.
For that matter, you don't even need the interfaces if you wouldn't have had them in a C#-only solution. Just define the class in F# and use it directly from C#.
You still need a separate assembly for F#, but that doesn't imply dependency injection - again, just reference it and use it.
gwbas1c 1 days ago [-]
I've identified a possible use case for F# in a preexisting product; I'm looking for the simplest way to integrate F#.
Lanayx 24 hours ago [-]
F# excels in writing domain logic where main domain entities are defined as records and discriminated unions and logic is written in pure functions. Given that product is preexisting and domain entities must already be defined, I wonder what use case do you have in mind?
gwbas1c 17 hours ago [-]
Realtime control logic for infrastructure.
The basic decision making logic needs to be very simple and easy to follow by scientists and people who aren't day-to-day software engineers: Basically, input some data, such as sensor readings, run it through an algorithm that makes decisions, and then output the decisions.
Aldipower 1 days ago [-]
"Why the F#?" perhaps would be a better title. :-)
twodave 1 days ago [-]
In the case of F#, the use cases are diminishing with every new C# release, since C# is getting better and better at the things F# is supposed to be strong at (record types, pattern-matching, etc.). Better to write the thing in C# using modern features of the more popular and capable language.
throw234234234 20 hours ago [-]
Not sure that C# is the more capable language - its still that F# is mostly a superset of C# although C# is catching up. I think they are on par w.r.t capability (i.e. CLR compatible). In terms of conciseness, and expression F# still wins IMO; and given some of the extra features can be more performant at times (e.g code templating/inlining vs just JIT attributes). Custom CE's (Async/TaskSeq), nested recursive seq's great for algorithm dev, DU's, etc. There's a lot of little features C# doesn't have (or don't quite fit) that when I write C# I'm forced to implement still more cruft code around.
IMO its generally more readable as well to non-dev than C# and to dev's outside the Java/C# ecosystem (e.g. Node, Go, etc). I've shown F# code back in the day to non-tech stakeholders and they typically understand it (e.g. data modelling).
arwhatever 23 hours ago [-]
Unions remain the killer F# feature missing from C#.
Also, basic object initialization in C# has turned into a nightmare with recent versions. You need a flowchart to select among the 18 syntax options which suite your current needs.
With F# (and other newer languages), record fields are either `T` or `T option`. No need to worry about whether the value needs to be computed in a constructor and then remain immutable, whether it needs to be initialized by an object initializer and/or a constructor or not, whether it needs to remain interior-ly mutable throughout the life of the record, and so on. (Although as I recall you do still need to consider null values assigned to non-nullable references in your F# code that consumes C#.)
marcosdumay 1 days ago [-]
You may start to get a point when C# gets a two-directional type inference system. As it's now, any functional-looking code requires so much boiler plate that it's shorter and less bug-prone to copy your functions code everywhere you want to use them.
int_19h 1 days ago [-]
Can you give an example of said boiler plate?
marcosdumay 4 hours ago [-]
Just try to make any generic high order function in C#. Any one you can think of.
DeathArrow 5 hours ago [-]
Using OneOf library or something similar instead of discriminated unions / sum types.
Trying to use a functional pipeline instead of DI.
DeathArrow 5 hours ago [-]
F# can be nicer to use for a functional programming style.
It's not always about the features such as keywords, built-in functionality and types. It's also how language features work together.
C# is more fit for an imperative or OOP style when F# is more fit for a functional style.
gwbas1c 1 days ago [-]
> Why F#?
I'm kinda wondering if anyone here with decent C#/.net experience can give their version of the answer?
---
The article really didn't answer its own question. It basically says "How" instead of "Why"...
...Which as someone who's spent over 20 years in C#, and tends to advocate for "functional" style, leaves me with more questions than answers!
kowalgta 1 days ago [-]
I've worked with .net professionally for almost 20 years. At the beginning with C# while last decade almost exclusively with F#.
F# is just a better language. Simpler, more concise, more readable with stronger type safety. I will never go back to writing C# as I'm finding it too frustrating at times and unproductive.
Foofoobar12345 1 days ago [-]
Everything is an expression (i.e. its an actual functional programming language), and along with it comes a different way of thinking about problems. Coupled with a really good type system which has discriminated unions, you'll have much fewer bugs.
Pro tip: don't write F# like you would write C# - then you might as well write C#. Take the time to learn the functional primitives.
arwhatever 23 hours ago [-]
if I may elaborate on "everything is an expression," F# allows you to do things like (with apologies for being a tad rusty with the syntax)
let bar =
if foo then
7
else
11
or
let bar =
try
// code that might throw
7
with ex ->
11
and will ensure that both/all code branches return a compatible type for the `let` binding.
Whereas in C# you have to do like
int bar;
if (foo) {
bar = 7;
} else {
bar = 11;
}
And C# will let you know if you omit the `else` on accident ...
Except that most C# developers do
int bar = 0; // or some other default value`
to get the red squiggly to go away while they type the rest of the code, unknowingly subverting the compiler's safety check.
This doesn't seem like a big deal given these examples. But it becomes a much bigger deal when the if/else grows super large, becomes nested, etc.
DeathArrow 5 hours ago [-]
Also C#:
bar = foo switch
{
true => 7,
false => 11
}
arwhatever 3 hours ago [-]
Ah yes that is definitely a nice addition to the C# language, albeit still with a couple of shortcomings compared to F#:
1. It doesn’t support code blocks, so if you need multiple lines or statements you have to define a function elsewhere.
2. To get exhaustiveness checking on int-backed enums you have to fiddle with compiler preprocessor directives.
And for #2 any data associated with each enum variant is left implied by C# and has to be inferred from a reading of the surrounding imperative code, whereas in F# the union data structure makes the relationship explicit, and verifiable by the compiler.
malakai521 1 days ago [-]
A nicer, cleaner and simpler syntax, superior pattern matching, active patterns, discriminated unions and computation expressions
int_19h 1 days ago [-]
C# has the equivalent of active patterns these days.
malakai521 1 days ago [-]
It does not
amelius 1 days ago [-]
I have a few questions. Can it do GUIs well? How about mobile? And how does it compare to e.g. Scala?
dagw 1 days ago [-]
Can it do GUIs well?
I don't know if I would say 'well'. For simple GUIs it's OK but, for non-trivial GUIs I would use the approach to write the GUI frontend code in C# and have it call the F# 'backend'. If for no other reason than that the support and documentation for doing GUIs in C# is much better.
How about mobile?
Never tried, but I'm guessing more or less the same story as above. I would probably start by looking into .Net MAUI for that.
And how does it compare to e.g. Scala?
The biggest difference is that Scala is a much bigger and more of a multi-paradigm language. F# feels smaller and more focused and on its ML roots and functional programming. Not saying that Scala is less 'functional' than F#, but Scala supports you writing your code in a much more OOP way if you want. Yes you can (and sometimes have to) do OOP in F#, but it doesn't feel natural.
Lanayx 1 days ago [-]
For web UI we have Fable and it's integration with well-known js frameworks, also WebSharper (although it's less well-known) and Bolero (on top of Blazor)
For mobile we have FuncUI (on top of Avalonia) and Fabulous (on top of Avalonia, Xamarin and Maui).
Most of these frameworks use Elm architecture, but some do not. For example I use Oxpecker.Solid which has reactive architecture.
Because it's a CLR language, it has access to all the same technologies as C#. That is, all the Microsoft native ones plus cross-platform with Avalonia.
.NET for iOS and Android is very robust, I’ve been developing with it since 2018. Just avoid using MAUI for interfaces because it's still quite unfinished after the rewrite from Xamarin.Forms.
munchler 1 days ago [-]
It can do GUIs well, although it takes some finesse to manage user state in an immutable-first language. Check out Fable for building web apps: https://fable.io/
I don't have much experience with Scala, but I think the two languages are pretty comparable in their respective ecosystems. The biggest difference I'm aware of is that Scala has typeclasses and F# does not.
int_19h 1 days ago [-]
F# is not really that strong on immutability, though. Sure, variables and struct fields are immutable by default, but making them mutable is one keyword away. Similarly with classes - declaring readonly properties is more concise, but when you need a read/write one, it's readily available.
jcmontx 1 days ago [-]
Sprinkle some HTMX next to your favorite template engine and you're g2g
Akronymus 1 days ago [-]
Which is what I am doing with my personal website for the most part. Elmish for the subpages where a lot of interactivity is actually needed. Otherwise just using Feliz.ViewEngine with htmx purely for enhancements
DeathArrow 4 hours ago [-]
F# is a lovable language as in people are really enjoying using it vs not being bothered using it.
Once every other month a new F# link lands on top page and receives a few hundred of upvotes.
I think F# needs and deserves more publicity in order for it to win a larger audience. If only F# community would be half as vocal as Rust community.
jxjnskkzxxhx 1 days ago [-]
Does anyone else find interesting that people who write blog posts saying "my favourite language is X", it's never a mainstream language..?
mrkeen 24 hours ago [-]
Successful language designers select for what's popular, not what's good.
C++ intersected the mass of C programmers with the new OO fad, and kept all of C's warts. Had Stroustrup made C++ better, he wouldn't have an army of adopters who already knew C. Maybe merit will win out in the long run [1]? I'm not hopeful.
Java needed to be close enough to C++, and C# to Java. And Brendan Eich joined Netscape to "put Scheme in the browser".
> people who write blog posts ... never a mainstream language
Don't you find it amusing that food critics usually write about little-known or new restaurants and never do any fast-food chain reviewing?
pantsforbirds 1 days ago [-]
My favorite language is Python, but I wouldn't write a blog post about it because no one would care.
jxjnskkzxxhx 1 days ago [-]
My favourite language is also python, and I would love to read your blog post on why your favourite language is python :-)
siknad 1 days ago [-]
New mainstream languages are rarer than new better (in some way that can be favorable) languages.
sklivvz1971 23 hours ago [-]
As a person who's worked with the author (a great guy!) and with the F# community on a very large F# project: don't bother with F#, professionally speaking.
F# has many theoretical qualities, which make it fun if you like these things, but it also has some fundamental flaws, which is why it's not getting a wide professional adoption.
- the build system was a mess last I checked (slow, peculiar)
- syntax is not c-like or python-like (a big deal for a lot of people)
- you can't hire developers who know it (and certainly the few are not cheap)
- the community is a bit weird/obsessed/evangelizing (a turn off in a professional environment)
- it's clearly a second class citizen in the .net world (when stuff breaks, good luck getting support)
On the other hand
- it has discriminated unions
- units
- etc.
but do you need this stuff (not want: need)? most people don't.
debugnik 7 hours ago [-]
The build system is exactly the same as C#, MSBuild with its .NET SDK, and syntax and community are entirely subjective; F# has the least weirdo community I've personally seen for an FP language. Weak arguments to say the least.
I'll give you the chicken-and-egg hiring problem and it being second-class to the .NET team, though; I'd add poor IDE support by modern standards, only Rider feels right. I love F# but I've moved on for these reasons.
FrustratedMonky 21 hours ago [-]
F# on front page? And popular?
ahhh, Its April Fools?
JK, I love F#. Please get over the hump and be a big language.
pdimitar 1 days ago [-]
People will do anything except actually try Elixir. :D
I tried F# some years ago (after I was fired from a shop that decided they will go all-in on Java and F# and dropping everything else overnight) and I was not impressed. I mean the language is really nice but the C# baggage and runtime was just a bit much. And I was not left convinced that immutability alone is worth the switch. I suppose we can call F# an FP gateway drug?
Now arguably you get a runtime and some baggage from the Erlang runtime (the BEAM VM, where Elixir also runs), but the guarantees and features you get are invaluable, and have proven themselves many times over the last literal three decades.
xigoi 1 days ago [-]
Elixir is dynamically typed, which presumably many people are put off by.
pdimitar 1 days ago [-]
Yes, I agree that it's a big drawback.
Elixir made me more productive and gave me back my love for programming, and I work with it professionally for 9 years now. But the lack of static typing is getting so irritating that I started upping my efforts to get [even] better at Rust lately.
So I agree. It's one of the very top drawbacks of Elixir.
weakfish 1 days ago [-]
The shop went all in on Java and F#? Why not C# and F#? That’s really odd, unless there’s context I’m missing.
pdimitar 1 days ago [-]
I wish they told me. They cut ties with most of their previous devs overnight, as if we were some enemies. Weirdest firing in my life and career to this day.
weakfish 1 days ago [-]
That’s truly bizarre. Glad you’re out of that situation, doesn’t sound quite healthy from what you’re saying.
johnnyjeans 1 days ago [-]
> Elixir
For me, it's Erlang. I just really like its horn clause syntax, it's so clean and readable. I know a common complaint is lack of piping (and even though you can implement it trivially, the order of arguments for some functions makes it of dubious use) but it's a small price to pay.
> I mean the language is really nice but the C# baggage and runtime was just a bit much
This was my experience with F#. Frankly, I've never been happy with my experience with CLI on Linux, and the toolchain inherits a lot of baggage from its C# heritage. Microsoft's toolchains have a very distinct workflow to them. F# has some interesting aspects to it like active patterns (something I wish was more common in the ML-family), but tbh I'm more than happy with ocaml.
innocentoldguy 1 days ago [-]
I can't remember which version of Erlang was the most current when I started learning Elixir, but I do know that it was years before OTP 20, which fixed its string issues. Prior to that, Erlang didn't have very good string support for internationalization (I do a lot of Japanese language programming). Elixir, on the other hand, did. Otherwise, I may have gone with Erlang back then.
I like Erlang a lot, too. Both are great languages.
BiteCode_dev 1 days ago [-]
If one need to get on Beam, is it better to start on Elixir or Gleam?
pdimitar 1 days ago [-]
Elixir's ecosystem is much farther ahead than Gleam, so if you want to actually achieve stuff without pauses to fill the gaps yourself, then Elixir is the way to go.
And don't get me wrong, I love the idea of Gleam, a lot (Rust syntax, strong static typing, what's not to love?). But my PL early adopter days are over.
DeathArrow 11 hours ago [-]
Iove the ideas behind functional programming but I never properly learned a functional programming language. I will probably never have the opportunity to use it professionaly and learning it just for hobby doesn't make sense to me.
If I am developing something in my spare time I also like to use something I can earn money with so I can hone and maintain my earning skills. Maybe sounds like min maxing.
If I would be in a situation where I can develop software just out of pleasure or pure curiosity, I would use just whatever language I deem interesting.
this_user 1 days ago [-]
Because you love using Microsoft's shitty technologies, but also want to be completely unemployable?
pacoWebConsult 1 days ago [-]
It's pretty baseless to claim that modern dotnet is inherently shitty. They've made tremendous strides in the dotnet core era.
F# making you unemployable is debateable, but I don't see what makes F# any less employable than most other FP languages. They have some niche applications that make it useful rarely, but when they're useful its a terrific tool for the job. F#'s ability to interop with the rest of the dotnet ecosystem positions it better than most functional languages for business usecases.
zem 1 days ago [-]
I'm sure Microsoft has developed a lot of bad tech, but by and large their languages have been great. msvc c++ compiler as a possible exception, but f# in particular is excellent.
gwbas1c 1 days ago [-]
I've spent my entire career, 22 years, primarily in C#.
I'm quite employable.
wiseowise 1 days ago [-]
> Because you love using Microsoft's shitty technologies
If we go by the joke in gp, this is you.
tialaramex 1 days ago [-]
I don't have any problem with the idea that Microsoft's technologies are "shitty" after all the response of my work laptop to its mandatory Windows 11 upgrade was a non-copyable diagnostic message with an opaque code in it which, as I understand it, is basically the equivalent of "Huh, oops, maybe try again?" and my colleague spent a week trying to uh, share data from a "Sharepoint" table.
But .NET's CLR doesn't seem especially shitty. It's not awesome, I don't feel that RIIR urge when I work with C# and I probably wouldn't with F# either but it's fine, it's like Java again, or maybe Go or Python. It's fine. I don't hate it and that's enough.
1 days ago [-]
RKFADU_UOFCCLEL 1 days ago [-]
F# is a very well-polished functional language. Think of it to Haskell as C# is to Java. No worries about space leaks or purely-academic syntax or monads (though you can get those if you need them). All with tight integration into one of the biggest, well-established ecosystem (CLI). It's managed by smart people who know how to keep it from derailing as it grows.
froggertoaster 1 days ago [-]
Coming from a .NET developer - why NOT F#?
* Network effect, or lack thereof. Very few people use it.
* Its nature is contrary to the ecosystem. The CLR is fundamentally resistant to the paradigms that F# creates.
Wonderful little language - one of my favorites - and we owe a lot to it for the great features that C# has. But it just hasn't picked up the critical mass it needs.
loxs 1 days ago [-]
I tried F# some years back when I was searching for a language to port my OCaml project in... It felt too much .NET-y and too much MicroSoft-y. And back then .net for linux had just been released and was somewhat unpolished.
It seemed that I had to learn C# in order to use F# properly and it seemed that porting it to C# was the saner option. I went with Rust after all and it seems to have been the right choice.
iLemming 4 hours ago [-]
> felt too much .NET-y and too much MicroSoft-y
That was kind of my main problem with dotnet stack in general, although that was some years ago. I've tried sneaking F# into our project by building set of tests (the main codebase was in C#), but some of my teammates would have none of that.
My personal perception of the dotnet community was that developers either were too pigheaded about doing things "the Microsoft way", or hyped about "innovation" — "Oooh... check this out, Scott Hanselman made a whole new conference talk about it...", and then you'd look into this "innovation", and it often turns out to be some decades old, well-known thing, only "wrapped into MSFT packaging", which is not really bad by itself - it just seemed that people didn't actually use them in a practical way. I just never found that sweet-spot between pragmatism and excitement. You have to find a middle ground between: "This works! Sure, yeah, but isn't it darn ugly and probably not scalable?" and "This is so beautiful, and cool, but nobody besides Jeff really understands it." And my personal experience was that .net programmers would always want to be on one of those sides.
airstrike 1 days ago [-]
This rings true to me as well. I'm not sure what I get out of F# that I can't get from Rust, unless you specifically want .NET, which I don't.
UK-Al05 10 hours ago [-]
Less arduous memory management.
airstrike 7 hours ago [-]
I am not sure what you mean. My memory management for a recent 30k LOC app boils down to "thinking before cloning"
DeathArrow 4 hours ago [-]
You get speed of development, productivity, lots of libraries. You get something that is easy to learn and understand.
airstrike 4 hours ago [-]
Lots of libraries if you want .NET, right? But if you don't, Rust has way more libraries
Speed of development is debatable. I think you can be pretty fast with both.
Easy to learn I concede but it gets easier with time, until it becomes very easy
fud101 1 days ago [-]
I want to ask a weird question. I'd love to learn ASP.net but i can't bring myself to deal with Microsoft Windows and their tech. Is F# a way for me to learn enough NET to make some money?
jcmontx 1 days ago [-]
I'm .NET dev and haven't touch a windows device since 2019. Work on Mac, deploy to Linux.
CharlieDigital 1 days ago [-]
I am also a C# dev and haven't worked on a Windows machine in 5 years.
C# and F# both work fine with Rider or VS Code on Mac or Linux.
lunarlull 23 hours ago [-]
> i can't bring myself to deal with Microsoft Windows and their tech
Even in a VM? Why not?
oguz-ismail 1 days ago [-]
>whitespace is significant, like in Python
hard pass
110bpm 1 days ago [-]
This isn't such a big issue in my experience. Auto-formatting helps a lot, the code needs to be just syntactically correct.
The default F# autoformatter is bundled/supported by VS Code, VS and Rider [0].
I don't think being whitespace-significant is a "hard pass" dealbreaker, but as someone who's not a fan of it, I'd say this only goes a small way towards alleviating that - like most "choose your preferred syntax" designs. Even if you're a lone-wolf developer, you're gonna end up reading a lot of example code and other material that's in the ugly whitespace-sensitive style, given that:
> The verbose syntax is not as commonly used ... The default syntax is the lightweight syntax.
And most people in practice are not lone-wolf devs, and so the existence of this syntax helps them even less.
lunarlull 23 hours ago [-]
You never touch python code either?
oguz-ismail 16 hours ago [-]
not since they binned 2.7
voidUpdate 1 days ago [-]
I was with it until I heard no braces :/
pjc50 1 days ago [-]
I have some good news for you about C#.
voidUpdate 1 days ago [-]
I love C#, its a great language
ahoka 1 days ago [-]
Perfect for blub programmers!
BeetleB 1 days ago [-]
C# doesn't require braces...?
1 days ago [-]
fire_lake 1 days ago [-]
Static typing removes the downside of whitespace.
Oh, and every language with line comments (so most of them) has significant whitespace.
AnimalMuppet 1 days ago [-]
> Static typing removes the downside of whitespace.
How so?
> Oh, and every language with line comments (so most of them) has significant whitespace.
Technically true, but that's not what people mean by "significant whitespace" in this context. So you're being pedantic rather than saying anything meaningful.
But you made me think. The ultimate nightmare would be significant trailing whitespace - the spaces and/or tabs after all the visible characters change the meaning of the line.
Akronymus 5 hours ago [-]
In f#'s case, there is the trifecta of everything being an expression, static typing and default immutability. This means you often write code like this:
let foo =
if bar then
baz
else
someDefault
Due to it being an expression you assign what the if evaluates to to foo.
Due to static typing, the compiler checks that both branches return the same type.
Due to the default immutability you don't declare and assign in separate steps.
What this results in, is that accidentally using the wrong indentation for something usually results in an error at compile time, at the latest.
Compared to how python does significant whitespace is that it's dynamic typing + statement based, which means you can easily end up assigning different types to the same variable in different branches of an if, for example.
I hope I explained it in understandable terms
fire_lake 2 hours ago [-]
Pythons approach to variable declarations makes this doubly bad.
Akronymus 2 hours ago [-]
Tbh, I've been successful enough in avoiding using python that I don't know the specifics of that.
fire_lake 1 days ago [-]
> How so?
Well I don’t know what issue you have with whitespace, but the usual complaint is that programs with small typos are syntactically valid but logically incorrect. This is why CoffeeScript became so disliked. A static type checker makes this scenario much less likely since it won’t compile.
I would also add that F# has some indentation rules (“offside rules”) and tabs are disallowed, further shrinking the input space.
fnord77 1 days ago [-]
> Trivia: F# is the language that made the pipeline operator (|>) popular.
laughs in clojure
nudpiedo 1 days ago [-]
Same as many, I had wonderful experience with F# in the past, I would use it again if:
- fable would 100% detach from dotnet
- keeps up yo the LLM rush, specially vibe coding on cursor
Last LLM experience it generated obsolete grammar (not much but a bit).
Such la gauges are key for vibe coding experience and modeling.
Being a stranger to Microsoft technologies, F# was the least likely to be chosen, but easily became the first choice. Haskell's purity made it hard to adopt (for me), Ocaml's ecosystem is subpar (there wasn't even a clear choice for a library to interact with postgresql, I couldn't install the latest version due to its reliance on an obscure tool whose name I forgot and didn't get help on the forum), and Scala is seems complex....
F# was surprisingly easy to get started with. The community is mis-managed by a corporate-minded approach (requiring people to become member of the F# software foundation to get access to the official slack!), but its members are friendly, smart and ready to help. The ecosystem is great with access to all the dotnet libraries (some complain there's a mismatch as most of those are developed for use with C#, but I rarely got in trouble for using them).
There are also great libs and frameworks available. Like https://github.com/SchlenkR/FsHttp to easily interact with http servers, to the point that I find it easier to use than a dedicated library. Or https://github.com/CaptnCodr/Fli , to run commands. And last but not least, https://www.websharper.com/ is the best web framework I have encountered across all ecosystems. Their reactive approach to web ui really allows me to develop complex interfaces in a maintainable way.
This became a longer message than I thought, probably due to my enthousiasm for the language. For complete transparency, the situation is not perfect, and in my experience the tooling is not the best.
If you want more info, I blogged about it a couple of months ago: https://www.asfaload.com/blog/consider-fsharp/
Having used Haskell in production for a bit now, I don't even notice its purity. Most functions are in some kind of I/O context making it similar as other languages, except with the option of running without I/O capabilities for functions that shouldn't need it.
These days I'd just do such a task more-or-less imperatively in Haskell, and I would be well guided by the types in doing so. But I also feel like you have to make a few such mistakes if you want to get a good intuition and taste for when it's good do things purely and when imperatively.
Another thing that was hard to grasp for me were the special operators like =<<, ., $, etc. I was using Xmonad, but those operators create a barrier to understanding exactly what happened in the file.
In the end, F# was in my (personal) experience much more approachable, and it let me learn the functional concepts along the way.
A few years ago on here I had an interesting conversation with someone who wasn't going to use rescript for something because they didn't like how it handled object types. I can't remember ever using an object type in rescript; we all just convert js objects to record type in the extern binding. But that's not information easily available to someone who has never used the language.
Same thing here I think. If you don't already have familiarity with this paradigm, it's hard to imagine what using an IO monad for side effects is like. It's not easy to tell how hard it'll be to learn it, how much it may affect the rest of your code, etc. It's easy to imagine someone (shit even me a few years ago) going "eh I'll take the language with the big easy escape hatches just in case."
This is a good observation.
As someone who writes a lot of Lisp, I'm inclined to agree as the amount of people that have never written any Lisp yet immediately reject it over syntax over fears that it somehow hampers development is a (to me) surprisingly large number of people.
If I recall correctly, one of the motivating factors for Rescript was to reduce the perceived/real distance between Reason and JS in order to attract more JS devs, as Reason was so heavily associated with OCaml.
Even so the complexity here and the sheer number of mind bending concepts makes me not want to use it.
Here's an example: as I said in my original message, I was a complete stranger to the dotnet ecosystem, and I learned the F# language at the same time. And I decided to develop the app as a library project to be used by the web app. I completely missed the prevalence of the async approach in the dotnet, and all my code was synchronous. One day, about half-way in the project, I realised I needed to switch to async code. Had this happened in a dynamically typed project, it would have been hell for me. Maybe it's me that can't grasp a project well enough, but I need the type-guardrails to find my way in large refactorings. And with the strong types, large refactorings can be done confidently. They don't replace tests, but make the refactoring process much more smooth.
The app is open source and its code is at: https://gitlab.com/myowndb/myowndb It doesn't have a lot of users, not the least due to lack of marketing and polishing the user experience. But I am satisfied of what I learned developing it!
On the other hand, "strong typing" isn't as quite as standardized in type systems terminology, but broadly speaking, it tends to be used to describe things like how "sound" a type system is (which is a well-defined concept in type systems theory), whether or not implicit type coercions can occur in the language, or other things that roughly translate to whether or not its possible for things to get misused as the wrong type without an explicit error occurring. Two examples that are commonly cited are JavaScript[0], with its sometimes confusion implicit conversions to allow things like adding an empty object and an empty array and getting the number 0 as the result (but not if added in the other order!) and C, with it being possible to interpret a value as whatever the equivalent underlying bytes would represent in an arbitrary type depending on the context its used.
[0]: I normally don't like to link to videos, but this famous comedic talk demonstrating a few of these JavaScript quirks is so thoroughly entertaining to watch again every few years that I feel like it's worth it so that those who haven't seen it before get a chance: https://www.destroyallsoftware.com/talks/wat
static typing: 2 + "2" does not compile/parse (e.g. Python vs mypy, Typescript vs JS)
this is a very simplistic example, but should get you to feel the difference.
I think this example is not correct, because static typing doesn’t affect how values of different types interact. And while I don’t know of any staticly typed language where specifically `2 + “2”` is a valid expression, statically typed languages definitely can be weakly typed: the most prominent example is C where one can combine values of different types without explicitly converting them to the same type (`2 + 2.0`).
I believe strong/weak and static/dynamic are orthogonal. And my examples are:
- Strong: `2 + “2”` is a error,
- Weak: `2 + “2”` makes 4 (or something else, see the language spec),
- Static: `var x = 2; x = “2”` is an error,
- Dynamic: `var x = 2; x = “2”` is fine.
But a dynamic language can have types associated with variables, and it can forbid changing those types after their types have been checked the first time.
[0]: https://gleam.run/
Even if is slower, the runtime model is incredibly resilient and it’s cheap to scale up and down, easy to hot update, and generally does asynchronous work extremely well across a lot of different processes.
F# has really good async ergonomics but it doesn’t have the same task/processing flexibility and Websockets are kind of a pain compared to elixir or even erlang
[0] https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?v...
[1] https://azure.microsoft.com/en-us/products/signalr-service
In the past, I found it wonky
F# on the JVM would be great though!
One caveat though: it seems FP matches my way of thinking. As an example, I always liked recursion, while some others saw it as complexifying things.
Try fsharp as fsx scripts to avoid boilerplate (see blog post linked in other comment) and you'll rapidly feel if you like it or not.
Even intellij has no idea sometimes about what the hell is going on. It throws up compile errors when there none.
However, the best functional programming language is, of course, Elixir. :D
Is there something about that that has bothered you? Working in Scala codebases, I've found the best ones to work in are the ones that embrace Scala's multiparadigm nature. When programmers try to solve every problem with OO, they end up adding more and more layers to get the job done. When programmers try to solve every problem with FP, they end up resorting to sophisticated techniques that are unapproachable for other engineers. I think the simple parts of OO and the simple parts of FP go much, much further together than simple OO or simple FP can go by themselves. Have you seen something different?
But they still miss the computation expressions, which open interesting possibilities like https://github.com/CaptnCodr/Fli and https://github.com/fsprojects/FsHttp
- Hot updates.
- Full distributed system support.
– Low-level process manipulation.
- Named processes.
- Advanced supervision strategies.
- Behaviours other than GenServer.
- Type-safe distributed messaging.
- And several other things that I value in BEAM and OTP.
I can't justify trading the full power of BEAM and OTP for static typing. To be fair, though, I've written a lot of code in both statically and dynamically typed languages, and static typing isn't something I value much (to the point that you might say I don't care about it at all :D).
Funny how preferences and priorities vary among devs, I need my static type system! :-) But note even in static type systems there are variations. I'm talking about an hindley milner type system with its type inference like the one in fsharp
it is functional (value) programming first. there are tools to hook in the object jvm stuff but this is not the natural grain of the language.
clojure is pretty much all values and functions (and some macroes).
+ some concurrency stuff
there is no class, there is no inheritance, you don't even have information hiding (no private etc.). you have protocols and multimethods.
(well technically there is private because java but it is not obvious to use and not what you expect, you will very rarely see that in clojure codebases)
honestly it is a nice small yet powerful language, with not too many kludges. my personal coding is either clojure or rust (which has way more kludges, but better than the other stuff in the typed fast compiled world at least for me).
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.
[0] https://survey.stackoverflow.co/2024/technology#most-popular...
Also, in the same results, just above Rust, I see:
<sarcasm> So, I guess that we can safely say that Microsoft PowerShell is still more popular than Rust. </sarcasm>But the moment you search Rust on LinkedIn, you can see the truth.
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.
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.)
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.
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.
I like F#, Haskell, Elixir but not Rust.
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
Last time I tried C++ with Copilot it was terrible.
Oh man, that is poignant :( They always say they do in the job description, but it always a different story once you get there.
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 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.
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.
Alternatively the task can be converted to a normal F# async with the Async.AwaitTask function.The 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.
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.
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 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)
It baffles me that there are languages with non-profit foundations and are financially backed by multiple corporations which still have bad build systems. It is the most important investment you can make into a programming language.
Secondly, often very differently shaped requirements. The dotnet SDK tries to keep its build specification (.csproj) files editable by Visual Studio, which is why most of the stuff in them is just XML properties.
You probably could build C#/F# with Bazel but that's not what Microsoft chose, and you kind of need to stay aligned with them and the large amount of MSBuild files in the SDK.
C++: invoke compiler for all compilation units, invoke linker to combine object files into executable
C#: invoke compiler once with all source files listed
F#: same as C# AFAIK, except file order matters!
C# has a multi-pass compiler so that it can compile and link the components from multiple files, without need of placeholder declarations, regardless of the order the symbols appear in the files.
F# has a single pass compiler, which keeps the compiler implementation simpler, but the file, and symbol definition order does matter that way. This is totally intentional, this is supposed to make the codebase more straightforward, with which I personally agree with. This avoids the need for declarations and centralization of them, the includes all the baggage that comes with that approach, and all the complexity C# has. I have rarely found a limiting factor, though there are some cases when it can be a bit inconvenient, for me the application setup/composition (~DI, but I prefer more static approach in F#) needed some cumbersome refactoring in some cases (have only vague memories by now, and yes, I know co-recursive types exists)
I really like F#, but rarely have to opportunity to work in it.
At the same time, a lot of the cool features (list comprehension, pattern matching, immutable records) have slowly trickled into c#, giving even less incentive to switch
On the other hand many of these features are really convenient and handy in F#. Adding many of the oh-my-gamedev-such-speed features from C# to F# also makes its syntax less pleasant to work with.
Personally I also think that the C# async model is terrible, and was a grave mistake. The F# async model with computation expressions, and explicit control over their execution context was a better approach, and I'm really sorry the hack-something-together to unblock the event loop WPF/frontend-dev usecase won over the more disciplined backend-focused approach.
Possibly `eval $(opam env)` is something that should just go in your ~/.zshrc
The OCaml folks have done some work recently to improve the onboarding documentation, which I think is going in a positive direction
e.g. https://ocaml.org/docs/installing-ocaml (the eval as a one-off post install command)
And then guiding people to use 'switches' https://ocaml.org/docs/opam-switch-introduction, which I totally missed when I started with the language.
> Local switches are automatically selected based on the current working directory.
You may not remember the early .net core times with yeoman and other then-current javascript ecosystem originated things applied in really cumbersome, half-assed ways, with lacking docs and always being in flux for years. The project.json era was terrible.
Also msbuild was way worse 10-15 years ago...
Mono with automake was special circle of hell IMO, I have very small exposure but it was really unproductive and painful.
I guess Microsoft could really make some headway if they got more folks to try it today.
Maven is awful. SBT is awful. Gradle is awful. I've used them all professionally, and the best I can say about them is that you can get the job done with them.
Newer languages and newer build systems are much better experiences, because of decades more hindsight and because language designers think about tooling from the start. Java was designed with the assumption that all software projects were built with Make, and with no ambition to improve on that. There was no Java-specific build tool until Ant was released as a standalone tool circa 2000.
> What is wrong with CMake for C++?
Granted, most of what's wrong with CMake is the problem it solves. Probably there's no solution that wouldn't be at least close to as awful as CMake. But it is objectively a hideous experience compared to any language created in the last 15 years.
My guess is that it's much longer than for the equivalent Java apps.
> What is wrong with CMake for C++?
It doesn't manage dependencies.
There are a few drawbacks, depending on your perspective:
- compilation is slower than c# and hot reload isn't supported (it's in progress)
- there are very few opportunities to use it professionally
- hiring devs can be challenging
For those who have already done functional programming, they wont take more than 2 days to start getting productive. For those who have written a lot of code, it will take them ~2 weeks to pick up functional thinking.
Anyone who is still uncomfortable with F# after 1 month - well that's a strong signal that the dev isn't a fast learner.
Additionally, I've never had anyone reject our job offer because we do F#. I'm sure a whole bunch of people might only be looking for python or javascript jobs, but that's fine because I'm not looking for them. I always have more people who I want to hire but I can't due to budget constraints.
Source: direct experience - I run a pure F# company with a team size of ~80.
For myself, I feel that I have "full" command of C# as a programming language, but also how to structure projects, how to isolate modules, how to decouple code, how to set up a build system from scratch for C#, how do deploy and scale applications built with C#, what the strengths and weaknesses are, etc. My definition of "comfort" would entail a broader understanding of not just the syntax, but of the runtime ecosystem in which that code operates.
I certainly wish I were doing f# professionally, but I only ever found 1 job listing for it, and that was in vienna while I am located like 200km away from it :(
Speaking of elm: I really like elmish for the frontend, when I need to make a dynamic page in the first place. Maybe that could be to your interest? (It transpiles to react under the hood via fable, which you can webpack into a drop in bundle. But I digress)
From the article, it looks like it's mostly dynamically typed. Or is it inferred? Or is it something else?
Like, if I write
Does that just work?To me, that'd be a point that might steer me away from the language. Deducible types seem vital to larger and long lived projects.
With regards to your example, the print/printfn (equivalent of Write/WriteLine) functions are a bit funny in F#. They don't actually take bound string values directly. You need to specify the type (which could be a string, a number, obj, etc)
https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
Given
The binding "hello" has "'a -> unit" signature where 'a is a generic argument it accepts because the "printfn" binding with a given format specifier is generalized the same way and an unconstrained 'T (here 'a) is the most narrow type inferred for "hello".Isn't gradual typing widely understood to mean "gradual between static and dynamic", which F# certainly isn't?
- hiring devs can be challenging
Those drawbacks are huge, IMO.
My experience was that it was a surprisingly nice language with a surprisingly warty user experience: papercuts ranging from naming conventions and function call styles (`|> List.map` vs `.Select`), basic syntax (`foo.[0]` to lookup arrays), type system features (F# doesn't have covariance/contravariance even though C# does), IDE support (back then was only Visual Studio, whose support for F# was inferior to C#).
Ended up settling on Scala after that, as a language with its own Warts, but one that somehow managed to feel a more cohesive than F# did despite having largely the same featureset and positioning.
F# was my first functional language and one that changed how I look at programming, but at the same time I'm happy to not actually have to use it for serious programming!
Array lookup in modern F# is just `foo[0]`.
Subtyping is much less common in F# than in C#, so the need for covariance/contravariance is correspondingly lower. Personally, I've never needed it.
F# support in Visual Studio is now excellent. You can also develop F# in VS Code.
F# feels kind of similar to Python in this regard, where there might be more than one way to do it, but there is community and ecosystem consensus on what is the right way.
I think a lot of credit should go to Don Syme for this; he seems to have a very clear vision of what F# should and should not be, and the combination of features ends up being very tasteful and well composed.
Being a hosted language always requires certain compromises (something that was also apparent in Scala). I used to do Scala professionally in its early days, but for me it felt it added just as much complexity as it addressed. I focused on Clojure back then (on the FP side at least), and I do think that F# probably brings more to the table than Scala. (if one is not constrained to Java, that is)
The tooling story is not great, but I've almost never seen great tooling for a language that's not super popular. I'm guessing what you get today with Rider is more or less as good as what VS has to offer.
I've always looked at F# with envy as it is a hosted ML that will have extremely battle tested bindings to the important day to day stuff via C# (Darklang's stories of struggling with postgres and AWS when using OCaml was a good cautionary tale on the risks of using less common langs as a startup)
Never had a chance to try out Scala but am a seasoned Clojurian, as an outsider it seemed Scala suffered a little from being not opinionated enough so the ML family has been more appealing to tinker with even though Scala supports type classes out the box and will also have great ecosystem support via the JVM
- Typelevel libraries: modern and more welcoming take on ScalaZ ideas, rich and mature, extensible libraries that are written in "tagless final" style.
- ZIO: concrete "super monad" with 3 type parameters, shuns the Haskell baggage and category theory lingo but pretty much the same concepts, compile-time autowiring dependency injection, a bit less mature.
- Kyo: new effects system on the block, pushing Scala 3's type system to the limit to stack effects using an "auto-flattening" monad (sorry if I butchered the description).
- Li Haoyi's own ecosystem that sticks to the standard library and JVM built-in mechanisms whenever possible, focused on Python style expressiveness, only more functional and with stronger types.
- I'd skip Akka/Pekko libraries but it's still an interesting piece of software if you need actor based, stateful cluster sharding.
Martin Odersky and the LAMP are focused on "capabilities" and we should eventually see something like direct-style algebraic effects, or like Kyo but without monads.
Also we have much better build systems than before (Scala-CLI, Mill, sbt has improved a lot too), binary backwards compatibility since Scala 3, and a very capable LSP backend if you don't like IntelliJ IDEA.
Though one thing I doubt c# ever gets that I love when I'm writing f# is pipeline operators. I love the way they read, from object/collection being worked on and then a list of operations being run on it in order from left to right (or you can do right to left if you need to for some particular reason).
Any tips? What kind of workflows might benefit the most if I were to incorporate it (to learn..)?
That is, each language will have its strong and weak points, but so far on "fluency" I’m not aware of anything that really beat Ruby far beyond as Ruby does compared to other mainstream programming languages.
>Crystal is a general-purpose, object-oriented programming language. With syntax inspired by Ruby, it's a compiled language with static type-checking.
But this time, one can probably say that Crystal will lake the benefits of ecosystem that only a large popular language enjoy.
I guess on that side F#, relying on .Net, is closer to Kotlin with Java ecosystem.
List<string> names = ["Peter", "Julia", "Xi"]; names.Select(name => $"Hello, {name}").ForEach(greeting => Console.WriteLine($"{greeting}! Enjoy your C#"))
or
new List<string> { "Peter", "Julia", "Xi" }.Select(name => $"Hello, {name}").ForEach(greeting => Console.WriteLine($"{greeting}! Enjoy your C#"))
To jump in a REPL (or any debug breakpoint observation facility), having optional type inference is a great plus to my mind.
Note that Crystal does allow to make type explicit, and keep the fluent interface on track doing so:
Let’s remark by the way that, like with C# lambda parameters, block parameters are not explicitly typed in that case.All the good stuff has been pirated from F# land by now: First-class functions, pattern matching, expression-bodied members, async functional composition, records, immutable collections, optional types, etc.
In the interim, MS demonstrates how C# 8.0+ can fake it pretty well with recursive pattern matching: https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
Not the same I know, and I would love me a true ADT in C#.
Edit (a formal proposal): https://github.com/dotnet/csharplang/blob/18a527bcc1f0bdaf54...
I assume you are implying that too many choices could confuse a junior developer, which I agree with. However, I don't think this is a concern in the bigger picture when talking about the space of all languages.
F# makes mutable code harder to do, so you tend to write immutable code by default.
For example, C# may have cribbed the language features, but F# is expression based and immutable by default. Try using the same features in this context and the whole game changes.
Maybe that's just research, and I'm glad that Microsoft hasn't killed F# (I do work there, but I don't write F# at work.)
It really isn't, not anymore. F# now evolves conservatively, just trying to remove warts and keep up with C# interop.
And even then some C# features were considered too complex/powerful to implement (e.g. variance, scoped refs) or implemented in weaker, incompatible ways when C#'s design is considered messy (e.g. F#'s non-nullable constraints disallow value-types, which breaks for some generic methods written in C#, sadly even part of the System libs).
In this case, I would move it to the very end if we are concerned about the underlying data shifting when the collection is actually enumerated.
Forgetting to materialize LINQ results can cause a lot of trouble, oftentimes in ways that happily evade detection while a debugger is attached.
I’m not sure what you mean by this. You can fulfill the IEnumerable contract without allowing multiple enumerations, but that doesn’t really have to do with the data shifting around. Doing ToList can be an expensive and unnecessary allocation
It seems reasonable to have it default to Array if it's ambiguous, maybe there's a downside I'm not aware of.
names.ForEach(name=>Console.WriteLine($"Hello, {name}! Enjoy your C#"));
I wrote a tutorial about how to get up and running with web dev in F# that might be of interest: https://functionalsoftware.se/posts/building-a-rest-api-in-g...
I see you use Giraffe but I wonder how hard would it be to use Web API or to mix F# projects with C# projects in the same solution.
F# popularity is somewhere between CHILL, Clipper and Raku langs, that are probably as obscure as F# for typical software dev.
https://3dpack.ing
Here's a rust ray tracer compiled to web assembly written in F#
https://ncave.github.io/fable-raytracer/
source: https://github.com/ncave/fable-raytracer?tab=readme-ov-file
Even if you never write a single line, it’s a fantastic illustrative language.
For example I refer to https://fsharpforfunandprofit.com/ all the time for functional programming ideas.
FWIW, I managed to learn Clojure without knowing anything from Java/JVM before diving into it. I did have plenty of JS experience which made ClojureScript easier to pick up I suppose, but Java works more or less the same as every other Algol-like and/or OOP language out there so if you have any previous experience with something like that, basic Java is trivial to pick up even accidentally.
They all seem to try and shield you from the fact that you are much better placed if coming from C# (which everyone seems to refer to as .net these days) and have a solid understanding of the .net class library.
All the main web frameworks sit on top of asp.net and pretty much all official documentation for that is in c#
Such a shame because I learnt so much about types from trying to crack f# for real world application. fsharpforfunandprofit taught me heaps which I apply to other languages, but I don't want to become a c# developer which comes with all the years of changing best practices to be able to really be productive in f#.
Sorry if I am coming across as bitter but I just can't see learning f# in isolation from c# which is an absolute shame.
I think if I ever have time for another go I would learn enough to be proficient in c# before diving back in.
Also, FSharp.Core (which most F# code leans heavily on) is not OOP at all.
F# promotes object programming, doesn't proscribe mutability, encourages function and data approach.
It offers simple access to the different paradigms, with some opinionated choices (e.g. preventing leaning on OOP beyond an arbitrary stretch, like no "protected", only explicit interface implementation, etc.).
https://fsprojects.github.io/FSharp.Data/library/CsvProvider...
For a more pragmatic take on static metaprogramming, the manifold project[1] for Java is worth a look. Unlike F#, which leans toward expansive schemas, Manifold focuses on contained, compile-time integrations—handling JSON, XML, SQL, GraphQL, and even other languages in a seamless, type-safe way.
1. https://github.com/manifold-systems/manifold
I know this isn't a common rant, but I hate so-called functional language still bowing to the "infix mathematical operator special case" dogma, when those are just binary (variadic in Lisp) functions.
Always found it pretty appealing, otherwise. And no ";;"!
This is a practical side of F# that doesn’t get enough spotlight — but one I’m using daily.
[0]: https://news.ycombinator.com/item?id=42636791
I’m not a dabbler in exotic languages, so this definition of “popular” was puzzling. I’ve literally never seen that operator before. Maybe I need to get out more.
It has been "stuck" at Stage 2 for a while, though.
We even do the frontend in it using Fable and Elmish, which is to say: we basically write our frontends in Elm, but the platform is .NET.
The flagship editor is Visual Studio, not vs code.
It's the one programming language that changed how I think about programming.
I'm only talking about the version before type providers. Then it got messy.
Before that, we could (and I did) recompile fsi.exe to do some custom prompt manipulation. It was a slog, but it worked, but then Microsoft faded from my life. Still, that early version (I believe 2.0) F# is just magnificent.
As for type providers in general, I don't think databases are the best example of their typical use case. Most type providers don’t interact with external systems; they usually parse schemas, configuration files, or other structured data to generate strongly typed representations. The database-backed approach is just one variant, not the norm.
Plus, I'm not going to be downloading, configuring, or running any separate code at runtime. The project is the project, it's going to process some files, communicate with some services, and communicate with the UI, if any.
If I need to consume a service, it should be defined such that I manifest the interface module (perhaps via WCF) and then connect to it progressively from stub to ever greater functionality in test to final implementation. Trying to write a program to do all that at runtime is not sensible, IMO.
Metaprogramming via reflection, however, was useful for exploring the vast .NET framework, and I used those to great effect, especially in exploring .NET's various UI frameworks (WinForms and Silverlight), but never to create code at runtime via the emit functionality. No, that's my job: to emit code that is tested and works and is comprehensible.
My current work needs nothing the .NET environment provides that I can't use python's standard libraries to get done, or bash and C if I need to.
But I'm lucky to no longer be in a corporate environment, so I don't need to consume commercial services, which was much easier using WCF within .NET. Back in my previous life, constructing n-tiered services on top of SqlServer using WCF was slick, indeed.
To any who are interested in how to construct such n-tiered applications simply but securely and precisely, I highly suggest Juval Lowy's IDesign system. He had three specific videos that I watched three or four times each until I understood his distillation of his vast expertise. Of course, Mr. Lowy is one of the co-designers of WCF, which was an excellent bit of tech.
It is controlled by Microsoft. It's not going on my Linux or BSD boxes.
I know how they work, and I want nothing to do with them.
Separately installed software? Not a bit of it.
That also, IMO, makes untangling/splitting up parts of the codebase easier as well.
I only used F# at its command line, fsi.exe, to give me commandline access to .NET for exploration, testing, and munging data. Over time, I built up quite a library of usable functions that I'd have the fsi.exe program pre-load when I kicked it off, leaving me at the prompt with all .NET namespaces and my code ready and accessible.
Once you get access to your database's data, it's easy to write queries against it and then play with the data. I could then port the F# processing bits that worked into my C# projects as necessary, but it was far easier to do it that way than to write the logic deep within complex multi-project solution files, where the various classes are spread throughout the projects' files.
I also just really enjoyed using F#.
I just gave a talk about how we use F# at REN: https://vimeo.com/1070647821
Otherwise, I am happy with OCaml, but F# has also a place in this world.
* It’s easier to attract smart developers to an F# project than to a [mainstream language] project. This was one of my driving beliefs when I introduced F# seven years ago. https://www.paulgraham.com/pypar.html. This is probably just as true for languages like Elixir, Clojure, ... But F# is what we went with.
Small Software Shop Context
* We operated in a small market where customers eventually dictated our tech stack (.NET & React). In that market, F# was a major advantage—it allowed junior developers to build apps that "just worked" with minimal regressions. Even with mediocre code quality, I felt confident that we could refactor safely at any time.
* I constantly had to justify F# to clients, which was exhausting. We always delivered decent results, so it worked out, but my partners were never as confident in defending F#.
Bootstrapping a SaaS Company
* F# has been invaluable for shipping features quickly and taking shortcuts when needed.
* Three years in, our codebase is large and contains its fair share of messy parts. But we can still develop new features at high speed with minimal regressions. Refactoring is relatively safe and straightforward.
* Compilation speed is the Achilles’ heel. If you don’t monitor it, the compiler slows down to the point where it impacts productivity. Earlier this year, waiting over a minute for feedback after a small change became unbearable. A lot of our "clean-up" work focuses on optimizing compilation times. We're still learning, but we’re optimistic that we can restructure the project to significantly improve build performance.
EDIT: maybe one more point. I see a lot of C# vs F# popping up here. Yes, C# has all the features that F# has. But do not underestimate how well designed F# is. It is an extremely simple language to learn compared to C#. There is a very limited amount of keywords to learn. And they compose extremely well. If you learned F# 7 years ago, took a break, and came back today, you'd simply write the same boring code that you would have written 7 years ago. And along the way you'd find out that some things have gotten a bit nicer over time.
https://fsharpforfunandprofit.com/posts/dependencies/
FWIW you can do it exactly the same way you do it in C#; it’s not “wrong”, it might just feel a bit out of place.
For F# , you need some basic C# knowledge For Clojure, you need some basic Java knowledge For Elixir, you need some basic Erlang knowledge
I like all 3 languages but usually each vm have a primary language, and each hosted language eventually become hosted on that primary language not the vm
I understand that for many task simple, to medium complexity, you might not need that, but it seem as you try to be more advanced you hit the wall of having to learn you host vm primary language
As an Elixir programmer, this does not resonate. Basically the only thing I've ever felt I needed to understand Erlang for was ets, but let's be honest, that's not really proper Erlang but just the terrible ets query syntax. And all this requires is "ability to read enough erlang term syntax to be able to understand the ets manual". I don't think I could write a single line of correct Erlang by heart.
I feel like that's different in F#, where you still need to know lots of .NET internals which are all documented in C#y terms with C# examples etc. Elixir wraps pretty much all good Erlang/OTP internals in nice Elixiry modules, which solves that quite nicely.
Elixir has its warts but this really isn't one of them.
Honestly, none of this really rings a bell. Having used all three options, I never felt that. Well, I already knew C# before getting into F#, but honestly, it felt like my C# knowledge at the time was more of a distraction. Been using Clojure for nine years, never done any serious Java and have not felt any need for it. Not knowing Erlang wasn't a problem with Elixir, like at all.
What bits of java have you ended up needing? Like do you often use java libraries that don’t have clojure wrappers?
I feel like I’m often running up against little things. I’ll google “how to do xyz in clojure” and the top SO answer is to use a java library that apparently everybody already knows about, cause so many clojurists came from java first!
The same with Clojurescript and JS (and probably with Clojure-Dart) - you have nice interop with the hosting platform. The need for learning anything about Java (while writing Clojure) basically boils down to finding API documentation for a specific class and simply using it. That's all. That's all you'd ever need.
You mark your functions and non-functions as such, so the compiler can get your back.
`task` targets the .NET TPL instead, which is also what C#'s await/async and all of .NET *Async methods use.
While the `async` implementation still offers some benefits over `task` (cold vs. hot starts [0]), my advice is - if you're doing backend code on .NET, you should use task. The tigher integration with the .NET ecosystem & runtime results in better exception stack traces, easier debugging and faster performance.
[0] https://github.com/TheAngryByrd/IcedTasks?tab=readme-ov-file...
Or: Is it more like the Swift / Objective C ecosystem where Swift, Objective C, and even straight C can co-exist in the same library?
In a mixed C# and F# codebase, generally when do you favor C# versus F#?
Coming from a C# background, what are the areas where F# is a better language?
Any success stories for F#, especially if it co-exists with C#? Any horror stories?
When mixing, you often write business logic as self-contained F# libraries with a C#-friendly API; and use C# to integrate them with whatever imperative, reflection-heavy and DI-heavy frameworks .NET is promoting the current year, since those are filled with interop edge cases for F# anyway.
You really want to avoid a language sandwich though (e.g. C#/F#/C#), because you'll keep wishing to remove the middle layer. Sadly, the addition of source generators make this mistake even more appealing.
The biggest advantage of F# is its gradual typing and full type inference which allows to massively reduce the amount of text required to describe application or domain logic. It is also extremely composable and I find doing async in F# somewhat nicer than in C# too. F# also has better nullability (or, rather, lack of thereof) assurances and, in my opinion, better UX for records.
1: C# Library with interfaces and/or abstract base classes
2: F# library with implementations of those interfaces and base classes
3: C# program (console, web service, GUI, ect) that specifies the implementations in Dependency Injection
Or is there a simpler way for C# and F# to co-exist in the same project (dll or exe)?
For that matter, you don't even need the interfaces if you wouldn't have had them in a C#-only solution. Just define the class in F# and use it directly from C#.
You still need a separate assembly for F#, but that doesn't imply dependency injection - again, just reference it and use it.
The basic decision making logic needs to be very simple and easy to follow by scientists and people who aren't day-to-day software engineers: Basically, input some data, such as sensor readings, run it through an algorithm that makes decisions, and then output the decisions.
IMO its generally more readable as well to non-dev than C# and to dev's outside the Java/C# ecosystem (e.g. Node, Go, etc). I've shown F# code back in the day to non-tech stakeholders and they typically understand it (e.g. data modelling).
Also, basic object initialization in C# has turned into a nightmare with recent versions. You need a flowchart to select among the 18 syntax options which suite your current needs.
With F# (and other newer languages), record fields are either `T` or `T option`. No need to worry about whether the value needs to be computed in a constructor and then remain immutable, whether it needs to be initialized by an object initializer and/or a constructor or not, whether it needs to remain interior-ly mutable throughout the life of the record, and so on. (Although as I recall you do still need to consider null values assigned to non-nullable references in your F# code that consumes C#.)
Trying to use a functional pipeline instead of DI.
It's not always about the features such as keywords, built-in functionality and types. It's also how language features work together.
C# is more fit for an imperative or OOP style when F# is more fit for a functional style.
I'm kinda wondering if anyone here with decent C#/.net experience can give their version of the answer?
---
The article really didn't answer its own question. It basically says "How" instead of "Why"...
...Which as someone who's spent over 20 years in C#, and tends to advocate for "functional" style, leaves me with more questions than answers!
F# is just a better language. Simpler, more concise, more readable with stronger type safety. I will never go back to writing C# as I'm finding it too frustrating at times and unproductive.
Pro tip: don't write F# like you would write C# - then you might as well write C#. Take the time to learn the functional primitives.
Whereas in C# you have to do like
And C# will let you know if you omit the `else` on accident ...Except that most C# developers do
to get the red squiggly to go away while they type the rest of the code, unknowingly subverting the compiler's safety check.This doesn't seem like a big deal given these examples. But it becomes a much bigger deal when the if/else grows super large, becomes nested, etc.
bar = foo switch
{
1. It doesn’t support code blocks, so if you need multiple lines or statements you have to define a function elsewhere. 2. To get exhaustiveness checking on int-backed enums you have to fiddle with compiler preprocessor directives.
And for #2 any data associated with each enum variant is left implied by C# and has to be inferred from a reading of the surrounding imperative code, whereas in F# the union data structure makes the relationship explicit, and verifiable by the compiler.
I don't know if I would say 'well'. For simple GUIs it's OK but, for non-trivial GUIs I would use the approach to write the GUI frontend code in C# and have it call the F# 'backend'. If for no other reason than that the support and documentation for doing GUIs in C# is much better.
How about mobile?
Never tried, but I'm guessing more or less the same story as above. I would probably start by looking into .Net MAUI for that.
And how does it compare to e.g. Scala?
The biggest difference is that Scala is a much bigger and more of a multi-paradigm language. F# feels smaller and more focused and on its ML roots and functional programming. Not saying that Scala is less 'functional' than F#, but Scala supports you writing your code in a much more OOP way if you want. Yes you can (and sometimes have to) do OOP in F#, but it doesn't feel natural.
For mobile we have FuncUI (on top of Avalonia) and Fabulous (on top of Avalonia, Xamarin and Maui). Most of these frameworks use Elm architecture, but some do not. For example I use Oxpecker.Solid which has reactive architecture.
Can't help with Scala comparison, but at least DeepSeek V3 prefers F# for UI https://whatisbetter.ai/result/F%23-vs-Scala-9eaede00c7e4485...
https://fsharp.org/use/desktop-apps/
I don't have much experience with Scala, but I think the two languages are pretty comparable in their respective ecosystems. The biggest difference I'm aware of is that Scala has typeclasses and F# does not.
Once every other month a new F# link lands on top page and receives a few hundred of upvotes.
I think F# needs and deserves more publicity in order for it to win a larger audience. If only F# community would be half as vocal as Rust community.
C++ intersected the mass of C programmers with the new OO fad, and kept all of C's warts. Had Stroustrup made C++ better, he wouldn't have an army of adopters who already knew C. Maybe merit will win out in the long run [1]? I'm not hopeful.
Java needed to be close enough to C++, and C# to Java. And Brendan Eich joined Netscape to "put Scheme in the browser".
[1] https://www.theregister.com/2025/03/02/c_creator_calls_for_a...
Don't you find it amusing that food critics usually write about little-known or new restaurants and never do any fast-food chain reviewing?
F# has many theoretical qualities, which make it fun if you like these things, but it also has some fundamental flaws, which is why it's not getting a wide professional adoption.
- the build system was a mess last I checked (slow, peculiar)
- syntax is not c-like or python-like (a big deal for a lot of people)
- you can't hire developers who know it (and certainly the few are not cheap)
- the community is a bit weird/obsessed/evangelizing (a turn off in a professional environment)
- it's clearly a second class citizen in the .net world (when stuff breaks, good luck getting support)
On the other hand
- it has discriminated unions
- units
- etc.
but do you need this stuff (not want: need)? most people don't.
I'll give you the chicken-and-egg hiring problem and it being second-class to the .NET team, though; I'd add poor IDE support by modern standards, only Rider feels right. I love F# but I've moved on for these reasons.
ahhh, Its April Fools?
JK, I love F#. Please get over the hump and be a big language.
...I mean: pipes, immutability, transparent mega-parallelism... helloooo?
I tried F# some years ago (after I was fired from a shop that decided they will go all-in on Java and F# and dropping everything else overnight) and I was not impressed. I mean the language is really nice but the C# baggage and runtime was just a bit much. And I was not left convinced that immutability alone is worth the switch. I suppose we can call F# an FP gateway drug?
Now arguably you get a runtime and some baggage from the Erlang runtime (the BEAM VM, where Elixir also runs), but the guarantees and features you get are invaluable, and have proven themselves many times over the last literal three decades.
Elixir made me more productive and gave me back my love for programming, and I work with it professionally for 9 years now. But the lack of static typing is getting so irritating that I started upping my efforts to get [even] better at Rust lately.
So I agree. It's one of the very top drawbacks of Elixir.
For me, it's Erlang. I just really like its horn clause syntax, it's so clean and readable. I know a common complaint is lack of piping (and even though you can implement it trivially, the order of arguments for some functions makes it of dubious use) but it's a small price to pay.
> I mean the language is really nice but the C# baggage and runtime was just a bit much
This was my experience with F#. Frankly, I've never been happy with my experience with CLI on Linux, and the toolchain inherits a lot of baggage from its C# heritage. Microsoft's toolchains have a very distinct workflow to them. F# has some interesting aspects to it like active patterns (something I wish was more common in the ML-family), but tbh I'm more than happy with ocaml.
I like Erlang a lot, too. Both are great languages.
And don't get me wrong, I love the idea of Gleam, a lot (Rust syntax, strong static typing, what's not to love?). But my PL early adopter days are over.
If I am developing something in my spare time I also like to use something I can earn money with so I can hone and maintain my earning skills. Maybe sounds like min maxing.
If I would be in a situation where I can develop software just out of pleasure or pure curiosity, I would use just whatever language I deem interesting.
F# making you unemployable is debateable, but I don't see what makes F# any less employable than most other FP languages. They have some niche applications that make it useful rarely, but when they're useful its a terrific tool for the job. F#'s ability to interop with the rest of the dotnet ecosystem positions it better than most functional languages for business usecases.
I'm quite employable.
If we go by the joke in gp, this is you.
But .NET's CLR doesn't seem especially shitty. It's not awesome, I don't feel that RIIR urge when I work with C# and I probably wouldn't with F# either but it's fine, it's like Java again, or maybe Go or Python. It's fine. I don't hate it and that's enough.
* Network effect, or lack thereof. Very few people use it. * Its nature is contrary to the ecosystem. The CLR is fundamentally resistant to the paradigms that F# creates.
Wonderful little language - one of my favorites - and we owe a lot to it for the great features that C# has. But it just hasn't picked up the critical mass it needs.
It seemed that I had to learn C# in order to use F# properly and it seemed that porting it to C# was the saner option. I went with Rust after all and it seems to have been the right choice.
That was kind of my main problem with dotnet stack in general, although that was some years ago. I've tried sneaking F# into our project by building set of tests (the main codebase was in C#), but some of my teammates would have none of that.
My personal perception of the dotnet community was that developers either were too pigheaded about doing things "the Microsoft way", or hyped about "innovation" — "Oooh... check this out, Scott Hanselman made a whole new conference talk about it...", and then you'd look into this "innovation", and it often turns out to be some decades old, well-known thing, only "wrapped into MSFT packaging", which is not really bad by itself - it just seemed that people didn't actually use them in a practical way. I just never found that sweet-spot between pragmatism and excitement. You have to find a middle ground between: "This works! Sure, yeah, but isn't it darn ugly and probably not scalable?" and "This is so beautiful, and cool, but nobody besides Jeff really understands it." And my personal experience was that .net programmers would always want to be on one of those sides.
Speed of development is debatable. I think you can be pretty fast with both.
Easy to learn I concede but it gets easier with time, until it becomes very easy
C# and F# both work fine with Rider or VS Code on Mac or Linux.
Even in a VM? Why not?
hard pass
The default F# autoformatter is bundled/supported by VS Code, VS and Rider [0].
[0]: https://fsprojects.github.io/fantomas/docs/end-users/StyleGu...
https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
I don't think being whitespace-significant is a "hard pass" dealbreaker, but as someone who's not a fan of it, I'd say this only goes a small way towards alleviating that - like most "choose your preferred syntax" designs. Even if you're a lone-wolf developer, you're gonna end up reading a lot of example code and other material that's in the ugly whitespace-sensitive style, given that:
> The verbose syntax is not as commonly used ... The default syntax is the lightweight syntax.
And most people in practice are not lone-wolf devs, and so the existence of this syntax helps them even less.
Oh, and every language with line comments (so most of them) has significant whitespace.
How so?
> Oh, and every language with line comments (so most of them) has significant whitespace.
Technically true, but that's not what people mean by "significant whitespace" in this context. So you're being pedantic rather than saying anything meaningful.
But you made me think. The ultimate nightmare would be significant trailing whitespace - the spaces and/or tabs after all the visible characters change the meaning of the line.
let foo = if bar then baz else someDefault
Due to it being an expression you assign what the if evaluates to to foo. Due to static typing, the compiler checks that both branches return the same type. Due to the default immutability you don't declare and assign in separate steps. What this results in, is that accidentally using the wrong indentation for something usually results in an error at compile time, at the latest.
Compared to how python does significant whitespace is that it's dynamic typing + statement based, which means you can easily end up assigning different types to the same variable in different branches of an if, for example.
I hope I explained it in understandable terms
Well I don’t know what issue you have with whitespace, but the usual complaint is that programs with small typos are syntactically valid but logically incorrect. This is why CoffeeScript became so disliked. A static type checker makes this scenario much less likely since it won’t compile.
I would also add that F# has some indentation rules (“offside rules”) and tabs are disallowed, further shrinking the input space.
laughs in clojure
- fable would 100% detach from dotnet - keeps up yo the LLM rush, specially vibe coding on cursor
Last LLM experience it generated obsolete grammar (not much but a bit).
Such la gauges are key for vibe coding experience and modeling.