4 ms·
F# has been my favorite language since I first encountered it in uni. F# was/is waaaay out ahead of C# with features like unions, null safety, pattern matching
by algorithmsRcool 2y ago
F# has been my favorite language since I first encountered it in uni.
F# was/is waaaay out ahead of C# with features like unions, null safety, pattern matching, records, more powerful type inference and generic constraints.
Over the years C# has been implementing these features too, which is good, but they have been implementing them in incompatible ways, which isn't very good. Since the investment in F# has been much smaller than in C#, it hasn't been innovating as fast as C# and has been left behind in some ways.
But it is still a great language and remains broadly compatible with the ecosystem and can deliver equal performance to C# with far less boiler plate
- neonsunset 2y agoMost incompatibilities can be summarized to "source generators" and tooling that relies on other forms of code generation. This can be fairly easily dealt with by writing a helper C# project with the necessary "glue". Other than that, is there something specific you have in mind? F# 9 even supports consuming ref struct generic arguments recently added to C# and plans to introduce their definition in F# itself AFAIK (which is likely going to be a nicer experience than in C#!). It has been doing impressively good job at keeping up thus far and deserves way more recognition for this.
- hansvm 2y agoOff the top of my head, async is monstrous to integrate between the two languages. Even when it works it's slow.
- neonsunset 2y agoThis was addressed in F# 6: https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-6#task- https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fs... Asynchronous sequences (IAsyncEnumerable) support is provided via https://github.com/fsprojects/FSharp.Control.TaskSeq https://github.com/fsprojects/FSharp.Control.TaskSeq F# is a very capable language - a broad spectrum of tasks can be solved by just implementing a new CE, something I could not even think of in C#.
- hansvm 2y agoKind of. It supports the C# Task interface nicely (and has for ages), but it you have a bunch of F# async code then you still have to marry the two somehow, and that's still monstrous.
- neonsunset 2y ago|> Async.AwaitTask ? Or is there a particular case that’s problematic? So far I have not seen any interoperability issues around this (even though yes, async CEs are way less efficient than task CEs) but I’m still learning so additional details would be appreciated.
- hansvm 2y agoThe two languages have two different async abstractions which at their core aren't compatible in general. When that happens in software, one of several possible options will happen. The thing Microsoft chose here is to give an API that looks like it's compatible but which is subtly broken for a nontrivial fraction of code (other common choices include rejecting any level of compatibility, providing more complicated APIs allowing the user to handle the multi-language nuances, or providing an incomplete API which works as expected). Much like how when one proposes a perpetual motion machine you know there must be a bug in the math somewhere, when somebody proposes an interop between two incompatible data structures there must also be a drawback. Pick literally any feature of the language other than sequentially executing code (exceptions and threads are usually great ways for languages and specs to fall apart), and you'll likely find places where the interop struggles. A few that come to mind: - That solution is only one direction. Interoperability needs to go both ways. - The exception interface between the two constructs is sufficiently poorly defined that I'd call it a footgun, and code that won't wake you up at night usually has to do extra work. - Performance in that kind of wrapping is a nightmare, both from the overhead of additional runtime layers, and, more importantly, because the last time I checked it was basically "sync over async" in a way that made the type system happy. - Going back to the exception thing, cancellation tokens are especially poorly handled in that interop one-liner. - They still haven't fixed blunders like ConfigureAwait(false), and the interop code absolutely has to care about that sort of thing in applicable contexts (the worst offenders being any sort of "main thread owns everything" code like current popular GUI paradigms).
- algorithmsRcool 2y agoThe F# team has done a great job of building compatibility bridges back to the C# way of doing things so the actual impact isn't bad.