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
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.
Asynchronous sequences (IAsyncEnumerable) support is provided via 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#.
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.
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).
Be nice please.
> Emotional
I'm not sure if this makes me sound more or less artificial, but outside the use of the word "blunder" there were scarcely any strong opinions, much less emotions.
> Few technical details
You came across as having done enough F# and C# to not need a novel to understand. Yes, those APIs are related to the problem of merging tasks and async between the two languages. 95% of the time you won't care, and 5% you'll hit a footgun. Just go write some multilingual GUI async code with a few cancellation tokens and exceptions and report back with the edge cases you find. The two abstractions are sufficiently different that you will necessarily find some, and if you aren't fortunate enough for your F# codebase to be mostly Tasks instead of async the you'll have to actually care.
> and if you aren't fortunate enough for your F# codebase to be mostly Tasks instead of async the you'll have to actually care.
My expectation is that async-based methods are not exposed to consuming from C#. If they are - this is unfortunate. The ideal state is to modernize the implementation and mainly rely on task CEs. Async CE has its advantages in terms implicit cancellation propagation but flowing down a cancellation token explicitly is usually a more pleasant experience than in other languages. Nothing that stands out as monstrous, and if something is - it has to do with the way a particular GUI framework implements it and not the language and platform themselves.
Last note on sync over async - threadpool can deal with it just fine. It has detection mechanism for this which proactively injects threads when a worker thread is expected to be blocked that bypasses regular scaling through hill-climbing.
Or, hell, just throw caution to the wind and text replace. I've heard some folks do that and it worked out well for them + wasn't much time to clean up either. They're especially happy to have better stack traces too.
The mind boggles.
At any rate, F# is a terrific language. After excel, probably the second best thing Microsoft has ever released. Turns .NET into a reasonable platform.
> After excel, probably the second best thing Microsoft has ever released. Turns .NET into a reasonable platform.
I feel like C# is quite underrated. Very productive language that's relatively easy to teach to anyone that is already familiar with JS or TS. Used in a variety of contexts from game engines to enterprise backends to desktop apps.A few fumbles by Microsoft early on stunted its growth, IMO, but it's a really good and relatively easy to learn general purpose language.
Microsoft really, _really_ missed out on a huge opportunity to rebrand .NET into something else when they did the Framework -> Core transition. Despite .NET being cross platform for over ten years and winning benchmarks left and right people still see it a the “slow enterprisey framework that only runs on Windows”.
I've met a handful of folks who used it in the .NET Framework days and hadn't kept up with the changes in Core (multi-platform, object-functional hybrid, minimal syntax for console and APIs, etc.).
https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/to...
(If there’s other syntax changes, I don’t know them, AFAIK it’s the same C# you write)
The new syntaxes that come to my mind are:
* File-scoped namespaces
* "global using"
* "using static"
It's a beginner friendly and "demo mode" set of features to reduce boilerplate for small programs, such that the minimal "hello world" program is literally 1 line of code.
And a working minimal ASP web app with a http endpoint is not much longer.
C# and .NET was from day 1 designed for "programming in the large" so that large codebases can be sensibly organised.
This however causes some overhead, such that a person coming from Python might have looked at the standard C# "hello world" example with using statements, namespace, class and method wrapping the 1-line payload, and conclude that the language is impossibly clunky and cumbersome. My opinion is the opposite; managing e.g. 50K lines of code without those ways of organising code, is going to be impossibly clunky and cumbersome.
However, it is also true that demo mode is great for 1-file demos that get right to the point.
Most of the verbosity comes from classes and namespaces. Go and Rust have shown it's possible to design a language for "programming in the large" without classes for everything and with less verbose namespaces.
But to be fair, I'm just getting started with C# so my comment above is likely wrong and biased. Happy to be proven wrong :)
> with less verbose namespaces
This is, once again, the function of the team and not the language. There is no hard mandate on how namespaces are selected so verbose namespaces is a result of teams preferring it over more concise naming. Part of that might be purely practical. Whereas in JS, you would import a local module by path, C# imports via namespace and convention is to use pathing, but C# will of course allow any namespace convention you like for local modules and does not constrain to strict pathing.The statement that "C# and .NET was from day 1 designed for programming in the large" is true and factual, supported by design documents that pre-date .NET 1.0, i.e. in the late 1990s
The statement that more-lightweight ways have since been developed of approaching the issue is more subjective. But IMHO it is also largely true, as the programming language world has moved on since then. The C# design has been extended a lot, but is constrained by being backwards-compatible. In some ways it is of its time.
e.g. We might not be "entirely sold on implicit usings" but it was a way to get from existing syntax, to a 1-liner "hello world". I think that global usings are fine, when used very sparingly. e.g. I am happy for a test project to have a global using Xunit because it will be used so widely in the project code. But not many more global usings.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...
Do these people I've never heard of outnumber the people who did upgrade but wouldn't have if it had been branded as a separate product?
Mind you, I’m not a coder, and more just a Linux homelab hobbyist.
How heavy of a dependency is it?
And is there a dependency hell situation, if different programs require different versions of .NET Core?
Size very much depends on what you actually use in the app, but on the order of tens of megabytes.
So you can ship .NET code with a .NET runtime all in your installer.
Afaik, Framework was only distributable from Microsoft.
After all, not being able to ship the runtime with the software to buyers would have been... Bad. In the early '00s
You can't run .NET Framework applications without a system install of .NET Framework.
You can absolutely run .NET (ex-Core) applications without a system install.
The state of .NET is something that Java wants to reach in a few years or so. There are basically three ways to deliver an application to the users:
- A single or multiple files containing .NET assemblies and a thin binary launcher (single-file mode controls the exact shipping of this) - this is similar to OpenJDK which requires a runtime to be installed on the system (except OpenJDK does not have the capability to put all assemblies into a single file with a small native section for the launcher).
- A single or multiple files containing .NET assemblies and runtime itself
- A single native executable compiled with NativeAOT
The first two options allow to "merge" assemblies into a single file or ship them separately.
Shipping just .NET assemblies without runtime takes the least amount of space but requires a runtime dependency (it's easy to install on practically any system).
Shipping assemblies + runtime can also be done as a single file where there's a sandwich of native code and .NET assemblies. In order for such executable to not take disproportionate amount of space (65-120+ MiB) it can be trimmed which is recommended - this reduces base binary size down to 10 MiB or less nowadays (and grows as you add dependencies).
And building with NativeAOT relies on the same linker-based trimming but produces a single native statically linked executable. This results in the smallest runtime-independent binaries (they start at about 1-1.2MiB) with the best startup latency but comes with a different performance profile when compared to JIT and is not compatible with features that either rely on JIT or on unbound un-analyzable reflection where ILLink cannot determine the exact scope of code that has to be compiled. The ecosystem has significantly improved since the introduction of this target in .NET 7 to provide users with tools to make their code compatible, if any changes are required at all.
AOT compilation has existed for about 20 years, it only happened to be a commercial product, Excelsior JET, Aonix, PTC, Aicas, are some examples.
What GraalVM, OpenJ9 bring to the table is free beer AOT compilers, and in GraalVM's case, a LLVM like compiler framework that doesn't exist at all in .NET land.
They also have the advantage of using agents to gather the required reflection data, instead of forcing an ecosystem split of having to rewrite existing libraries to make them AOT ready.
There was the Phoenix project from Microsoft Research, which had the goal to replace Visual Studio infrastructure with a CLI based compiler toolchain, but unfortunely that project failed to gain traction within Microsoft.
Shipping runtimes, which .NET Core introduced for .NET, has been a thing in Java land since they exist.
There is also the ability to create single executables, coupled with jlink and jpackage.
Besides OpenJDK offerings, there is a richness of JVM implementations, each to those having other capabilities, like OpenJ9 and Azul with their distributed JIT compiler for example.
.NET is great and I prefer .NET to Java consulting projects when given the option, however it is no accident that Microsoft has decided to become again a Java vendor as well.
This has been moot for a long time now, though, since Windows has shipped with some version of .NET preinstalled since Vista.
Pretty much yes. (there are also other ways to bundle it)
It's not even called ".NET Core" any more, it's just ".NET", which for version >= 5.0 effectively is the successor to cross-platform .NET Core.
.NET 9.0 will be out shortly - The annual release is expected November 2024, likely this week.
> dot
> dot console apps
> dot web API
> dot desktop apps
Simple logo design.CLI commands would be like:
> dot new console
> dot build
> dot run
> dot publish
(Yes, I know I can alias)It's not too late, Microsoft!
You may still find some JREs, which are created by some distributions that take the stuff out of the JDK to make classical JRE, though.
What should be "do a thing" is now design a thing to do a thing then call the thing-do-er IDoAThing.
Alone this would not be so bad but the problem is that you only have this. Extension methods? Fuck off (but don't take them away).
Roslyn is great though.
Also, extension methods are great. LINQ is amazing and that's partly from extension methods.
You can call it a hack but IMO you get the best of both worlds.
It's adding optionality and in fact, doesn't in any way break OOP at all; it is syntactic sugar.
There's reflexivity and path dependency but the culture is downstream of the values for the most part.
> C# culture is closer to enterprise Java than it is to Typescript
I mean, this really depends on what you're looking at.Here's a sample from the MongoDB client: https://github.com/mongodb/node-mongodb-native/blob/main/src...
Here's a sample from Storybook: https://github.com/storybookjs/storybook/blob/next/code/core...
Here's a sample from Prisma: https://github.com/prisma/prisma/blob/main/packages/client/s...
Here's a sample from Cal.com: https://github.com/calcom/cal.com/blob/main/packages/core/Ev...
These are all fairly mainstream repos so it's not a one off to see "enterprise" style coding in TypeScript.
It's rather the specific use case that determines the style of the code that's written. In the examples above, there's no need for the teams to choose JavaScript classes and inheritance to model the logic, yet it likely better fits the programming model of those modules.
Look at Nest.js as well: https://github.com/nestjs/nest/blob/master/packages/core/rou...
The whole codebase of Nest.js looks an awful lot like Spring or ASP.NET (controller syntax) probably because there's a lot of crossover in terms of what APIs need at scale and how to logically organize that logic.
It just so happens that most use cases for C# and Java favor applications at a larger scale. Another key difference being object scope and lifecycles -- something that rarely comes into play in the generally single-threaded Node runtime. This being one of the key reasons why dependency injection is a thing in C# and Java land.
I kind of think the best languages would be those that make creating layers of spaghetti indirection nearly impossible. In practice, it's usually much more specious. Names like "CreatorImplementer", "FactoryAbstrator", "DeviceAccessory" and a half dozen equally amorphous things calling each other as if Thomas Pynchon was writing software.
I think I've seen it in all languages I've worked on professionally. Maybe not in Perl.
I keep remembering this code I saw in 2014. It was in ember and used mongodb and some bizarre ember features I've long forgotten to stylize things instead of conventional stylesheets.
I had been doing JavaScript since it was called LiveScript in 1995. I knew it very well. This setup was utterly impenetrable. Charging a button color required I think 6 or so different data stores to be manually updated and placed back in alignment because things were validating and cross checking for no good reason other than being a complicated pile of tangled messes. I had to quit the job.
I know how incredible this sounds. I can prove it. He does everything like this. Here you go https://github.com/davideschiera/flame-ui/tree/master ... I'm not quite sure what these 252 files do but I'm pretty sure it could be done in about 25 lines of code in a single function.
I had worked with him previously on a C# codebase almost 20 years ago now. I remember him being just as insane but somehow the language successfully encapsulated the insanity so I never had to deal with it.
There's this fundamental clash. I think things should work, be maintainable, and have the most minimally complex implementation possible - the Ernest Hemingway approach. Some people prefer James Joyce.
I think that F# goes a long way to prevent this, by nature of being functional.
Are you taking about the popularity of the mediator pattern (via Mediatr)?
Additionally, Microsoft has an outsized influence on the C# ecosystem. As a result, they wrote quite a few architectural and style guidelines that, naturally, target themselves. It makes sense for a hyper-widely distributed library to consider things like binary compatibility as critical features, but the design rules that follow from that have zero utility for apps, and low utility for most libraries. The C# ecosystem also has an unhealthy veneration for MS provided code. While I'm sure most of the authors are quite competent, there's less experimentation and fewer hidden gems because the ecosystem is tilted towards being followers behind the framework providers path.
As a result, it's much harder to refactor code in that style than code in a less (runtime) flexible style, and it's worse when the libraries heavily used are frameworks that have so many extension points. There's a tradeoff between runtime flexibility and codebase flexibility, and the default .NET C# style heavily leans towards runtime flexibility, which isn't a good tradeoff for most software.
MediatR is part of the problem, yes. Way too much attribute/reflection magic there.
One particularly good example is: attempt to add full support (i.e. query text generation) for PERCENTILE_CONT to EF. That will give a good idea of just how bad the idiomatic C# style can get. Now take the EF style of code/architecture and apply it to an entire product codebase - which is completely a understandable mistake to be made (it's not unreasonable to assume that EF would be a good example of C# code). You know you have a problem when you throw in the towel and have ThingDependencies classes all over the place. The aspnetcore internals don't vary too much from the abomination that is EF.
"Just don't code like that," you might say. The problem with that argument is that pre-existing code exists, people don't code in isolation, and the cargo cult has a ton of momentum behind it.
> your comment about F# being different.
You'll struggle to write that style of code in a functional language. There is such as thing as healthy friction. F# has its own problems, but this is not one of them.
My experience is that it's "fire and forget"; never give it much of a thought at all and isn't much different from:
// some-module.ts
export const someModule = () => {
}
// other-module.ts
import { someModule } from "some-module"
Except that DI allows "importing" at different levels.That’s fair, I consistently underrate it myself. Last time I worked with C# was a big messy codebase written by mostly junior developers who didn’t understand what entity framework was doing behind the scenes. I came away from that experience with the impression that C# is a terrible language.
I say all this as someone who loves F# and would only take a C# job if I needed the money. But certainly a lot of the enterprise antipatterns can be clumsily implemented in F#, while a well-written C# codebase is usually pleasant and productive. In particular F# doesn’t totally escape problems like “the Nuget service locator is overengineered for our needs, but we are on a deadline and an excessive abstraction is better than hard-wiring everything.”
And line for line, F# is more effective at getting things done (and i would argue with less bugs)
What about Java?
IMO to be productive in F# code code tends to be simpler - many patterns that dev's valued learning in a OO context become a little obsolete or less needed as a whole. This is my anecdote but it is the C#/Java/etc crowd that tend to have the most negative immediate reaction to F# - they ask "where is X" and often I immediately say "X is bad, you shouldn't need X - think about why". They associate X with some kind of power/productivity gain, but don't realize there is many ways to do things. Kind of follows the paradigm of "frameworks/patterns are missing language features".
If they keep at it then it eventually clicks but there is almost a psychological "unlearning" that needs to be done which at least in the C# camp creates an almost tribal tension between the two camps - its just too unfamiliar. Whereas for example TS dev's seem to find it somewhat familiar in parts; even people only ever done JS previously I've found have become good F# dev's. Could be because the flow more suits the way you would code in a dynamic language while still being strongly typed (e.g. REPL's, type inference, static modules, functions over classes, etc).
Check out my small repo here showing how similar they are: https://github.com/CharlieDigital/js-ts-csharp
Any downsides, in your opinion?
I had toyed with it a few years ago, using that lightweight IDE called LINQPad, IIRC, but did not follow up, or keep track of its pros and cons or progress later.
It's a shame because F# is a beautiful language — it's fun to read, write and maintain. .NET now works well cross-platform with editors other than Visual Studio. General perks of .NET like cross-platform compilation are a nice bonus, for example, on macOS I can:
brew install dotnet
dotnet new console -lang F# -o HelloWorldApp
cd HelloWorldApp
dotnet publish -c Release -r osx-arm64 --self-contained
dotnet publish -c Release -r osx-x64 --self-contained
dotnet publish -c Release -r win-x64 --self-contained
dotnet publish -c Release -r linux-x64 --self-contained
To get self-contained binaries (that don't need .NET to be installed locally) for those platforms.There is a decent multi-platform UI framework called Avalonia: https://github.com/fsprojects/Avalonia.FuncUI
There are good actively maintained web frameworks: https://fsharp.org/guides/web/#web-frameworks
There are some passionate people writing great books about F#: https://fsharpforfunandprofit.com/ddd/
Most of F#'s adoption issues seem to be because:
1. It's tough to convince people outside of the .NET community to use .NET.
2. Most of the people using .NET use C#.
3. It's hard to convince C# users to adopt F#. (See https://www.reddit.com/r/dotnet/comments/16m0wdj/why_dont_yo... and similar threads.)
I'd love to work with F# full-time, but — short of starting my own company using it or convincing Microsoft to pay me to help them showcase its benefits — it's been hard to find work with F#, which drove me to spend time with other languages.
dotnet publish -o {folder} -p:PublishAot=true
Note that -c Release is no longer required - it is now a default for 'publish'. Also, if you are doing a self-contained/non-AOT build, you may want to do it as follows to retain compact binary size: dotnet publish -o {folder} -p:PublishSingleFile=true -p:PublishTrimmed=true
All the properties above can also be defined within respective .csproj/.fsproj files inside PropertyGroup blocks as e.g. <PublishAot>true</PublishAot> so you don't have to add them to a command every time.F# also has excellent support for scripting with fsi and .fsx format: https://learn.microsoft.com/en-us/dotnet/fsharp/tools/fsharp...
Someone even made a tool for it which builds on top of bflat allowing to compile F# script files into native binaries directly without project setup: https://github.com/ieviev/fflat
Compare that to starting to read Python when you come from C#, it reads as English.
F# omits much more in its code.
It feels like typed lisp with the brackets omitted.
Yes, the language make a lot more sense if you know how to do that compared to if you don't.
But that’s the thing about F#: the grammar isn’t arbitrarily complicated. It’s really quite simple, which is why mentally inserting lispy parentheses helps me reason about it.
Both of these are surprising to me. It is an indentation language, similar to Python which I love. And it was by Microsoft, which makes Visual Studio which I also loved
Yet I found the syntax a lot odder than Python: multiple ways to call methods (C# style and Ocaml style), a wide selection of strange brackets, `.[i]` for array lookup instead of `[i]` (i think they fixed this eventually). And despite Visual Studio being great for C#, its support for F# wasnt up to scratch
I ended up settling on Scala, which is semantically very similar, but with an easier syntax (not perfect, but better) and decent Intellij suppory (again, nowhere near perfext!)
There is no other platform like .NET in capability to cover both high and low level scenarios.
[1] https://odin-lang.org/news/newsletter-2024-10/#interview-wit...
I suppose it’s a chicken and egg problem for languages that want to grow their communities (if nobody takes risks on a language it won’t see adoption) but I’m surprised given their problem domain they didn’t go with something more widely known
It's perfectly fine to use an LLVM-based language where it matters, but it's sad when C# could have been used to solve the problem without throwing the baby out with the bathwater.
IMV it thrives in back-end scenarios where correctness, and algorithmic work could occur whilst still needing some speed of development and a large enough ecosystem. It typically doesn't live in large teams hence less jobs but the teams that I've been on that use it have far reach/leverage once they are proficient at it. I've been lucky to be a part of more than one team like this.
Other languages do this too as well (Rust, Go, etc) with different tradeoffs - F#'s advantage to me is if you want easier learning of staff, correctness, interoperability, faster development IME, scripting at times and reasonable performance (e.g. C#/Java/etc class). It's rare you feel you are fighting the language or producing boilerplate or repeated code patterns; at least in the domains I've used it in. At least in my use cases it is the jack of all trades kind of language; that is its problem as well as its strength.
How so? Or do you mean that about list, dict and set comprehensions?
After over a year of trying to make it work, we completely rewrote the application in Typescript and Rust. The product we're building is an end-user programming tool where the traditional lines between front-end and back-end work blur, and the .NET ecosystem really didn't lend itself well to this.
Our hope was that we'd be able to use the Fable library to maintain type safety across a variety of technologies while being able to interop and in and out as needed: Fable compiles F# code to JS, Rust, .NET, etc. The reality was that the interop story between the various libraries we'd use was much harder to achieve than initially expected, and managing and updating multiple dependencies and their bindings was an absolute PITA.
The assumption that F# makes for beautiful, efficient code is still a safe one, I think. But the ecosystem and the way that it was designed makes it (in my view) applicable only for applications and software that have very traditional frontend/backend lines. F# would be used for the back-end only in that case.
Today, two of the technologies I'm most excited by (and which we're using internally) are the Effect library, whose Schema library fills in a lot of the gaps in TS's type system, and Moonbit, which is what I imagine a modern version of F# would like, free of the MS/.NET dependencies. Moonbit is really, really well designed (designed by the creator of OCAML's version of Fable, ReScript), and it compiles directly to highly optimized JS, WASM or Native output. We're using Effect in production, and not yet Moonbit, but the promise Moonbit holds as a language built for an AI-first world is pretty fantastic.
Effect is pretty nice, I wish it existed in other languages than TypeScript too. Regarding MoonBit, it seems like its own proprietary programming language so I'd hesitate to move to that over something well known, what are your thoughts on that aspect?
https://devblogs.microsoft.com/dotnet/performance-improvemen...
I always thought the tooling was quite good, given the size of the community and Microsoft's apparent apathy towards it at times. The biggest pain point for me was accuracy in code test coverage.
I hope to have time to build a small web backend project this winter, to get to know the language and ecosystem better.
I heard good things about Oxpecker for the http part; do you have any recommendation for a good postgresql client/driver ? (I don't like ORMs)
- https://monazita.gitlab.io/monazita/ (i developed it for a project of mine while learning fsharp. Basically works but could be more polished and is pgsql only)
- https://github.com/jacentino/DbFun (more polished than previous project, and multi db)
Another comment mentions .NET9 that recently came out, is that the reasoning here, to keep in stride with .NET version numbers?
That means, for example, that the F# team _could_ have shipped a language change between versions 8 and 9, but if they didn't then at least they could have shipped a compiler change or an msbuild change that required .NET 9 for whatever reason.
For developers, usually you can just update your code to the latest available runtime version unless you have to wait for your deployment environment to have the latest .NET version installed. Nowadays that's not necessary due to MSBuild changes to create self-contained deployments, but something to know.
C#'s (lucky) 13.0 in .NET 9 is also just partly related to the non-linear version numbering of .NET itself with the long shadow if .NET 4's many minor releases that were also "major", the Core divide, and the eventual "unfork" at 5.0. F#'s 9.0 matching .NET 9 is a fun coincidence, and also just because F# is younger and missed some of the .NET fun like 4.x "minor number is as important as major number" years.
https://github.com/fsprojects/Avalonia.FuncUI
https://fabulous.dev/ (which targets Avalonia/MAUI/Xamarin)
https://github.com/kekyo/epoxy (Avalonia and WPF)
> Are there companies using F# for this purpose?
I can ask around if you're interested.
Since it's pretty tiny minority of .Net users use F#, I'm sure someone somewhere is using F# for GUI but it's going to be tiny shop somewhere.
Is it like a windows thing that you can also do on Linux or does it feel like a fully supported language?
So we are mostly left with the community doing most of the work in a company with enought money to burn in deals like the Actvision Blizzard one, but not to staff the F# team appropriately (and they aren't the only one in such a state).
It could use more marketing, halo projects and word of mouth though.
And if consider Google to be a platform vendor with hands on Kotlin, then Android / Kotlin development experience is certainly much better than F# has ever achieved since its Visual Studio 2010's introduction.
What F# has going for it, despite everything, is its great experience on Windows, versus Haskell and OCaml, which remain UNIX centric at heart.
When should you prefer immutability over mutability since both are possible in F# and it probably has a measurable impact on performance?
When should you use objects instead of records or unions in F#?
Since mutability is possible, any reason to not allow an explicit return or continue? It makes certain code patterns much less nested and easier to read.
Allegedly, of course. I'm sure Wal-Mart PR will happily tell you it was their own idea and how Java is the language of the future again, or something to that effect.
Also, whether or not the rumors hold, it is hard to discount the pure Occam's Razor that it was just Wal-Mart's own idea to cut costs because of the simple dumb fact that labor costs in Wal-Mart's home labor markets for Java developers are certainly cheaper than .NET developers in the same job titles/experience levels. A mandate to switch to Java certainly was one cheeky way to do a slow layoff of expensive laborers without doing a real layoff.
As someone that does consulting across multiple programming languages, what I notice is that .NET is too late to the party in the server room wars.
For better or worse, UNIX and ideas derived from it, won the server rooms and cloud deployments, even Azure is mostly Linux nowadays (> 60% as per official numbers).
Due to its previous history, .NET has always had a bad name in UNIX shops (even with Mono), and most companies would rather use something else, unless they are a Microsoft shop, it could be Java, Go, or whatever.
As far as I am aware, Wal-Mart isn't a Microsoft shop and only acquired Jet for the business, not the technology, so like in all acquisitions something like that was bound to happen.
I've never worked for Wal-Mart, I've only seen PR and blog posts and job postings. That is likely its own spin of what happened, too. But during those years Wal-Mart was seen as a stable "Microsoft shop" in terms of what they were hiring for in software developers (if you didn't mind relocating to Arkansas).
Externally, the Java thing did seem to be a "coup" that came out of the blue. Like I said, the easiest explanation is that Wal-Mart, a company famous for ruthless cost cutting and layoffs, felt like they had milked their acquihire of Jet for just long enough to stay competitive and decided the easiest "exit" for those expensive employees was to force a top-down mandated tech stack change to a known cheaper tech stack and gently encourage them to quit on their own initiative in the chaos. (In that Wal-Mart was already very quick to RTO, they had already played that particular card, many other companies are still palming to cause similar layoffs.)
The Oracle rumors are icing on the cake, sure. But also extremely plausible given that is how Oracle's business works today.
All it takes is a moment of inattention to screw up.
Unfortunately, maintenance seems to have stopped since Jan,
https://github.com/fsbolero/Bolero/releases
(I tried creating a sample project on Linux which didn't work to begin with)
If you have any specific examples of discoverability/reusability issues in F#, I'd be curious to hear them.
Anyone familiar with both that can compare them?
This change in F# makes it able to interoperate with C# NRTs, where C#'s T? becomes F#'s T | null and vice versa.
I feel like the ease of integration of F# into existing codebases is one of the major selling points. You don't need to write wrappers in order to consume most existing C# code, which, for example, enables writing a core with business logic in F# while keeping the IO in C# if necessary.
---EDIT---
Mean to post this under the GP
When did F# get unions?
Wonder if they will generalize: https://github.com/fsharp/fslang-design/blob/main/RFCs/FS-10...