I'm not entirely sure why this is getting downvoted. I'm a moderately noisy FP fan myself, but this statement does seem, on the balance of evidence, to be true. I'm interested to know why.
Maybe because dismissing those who appreciate the advantages of functional programming as "noisy fans" is condescending, and implies that their preferences are based on emotional rather than rational grounds. I'm not a noisy fan of FP at all, but I like a lot of concepts (like immutability), and I do adapt them in my code
I think noisy fan was meant to imply that people who are in favour of functional programming languages tend to be more vocal in their views, rather than those who are in favour of imperative programming languages.
This is probably because imperative languages are the majority, so there's no need to soapbox, rather than anything related to the communities or the merits involved.
The impression is that their preference runs on the ideological/pragmatic divide rather than the emotional/rational. (Not that I wouldn't want to be an FP samurai myself, along with exercising more regularly, flossing, and achieving inner peace )
And that seems to be sufficient cause for the FP enthusiasts to lose their shit in Go threads.
That sort of thing is the only exposure many of us have to FP people, for better or worse. When they pop in to tell everybody they're doing it wrong in the craziest fashion possible.
Probably because what we're taught as programming is imperative programming, then moving on to OO, etc. If we were taught FP from the start (we, broadly speaking), then people would probably be fans of FP.
It's funny how SQL is a declarative set-language, very different from imperative and other paradigms, yet nobody seems to bat an eye about it having its proper place and role.
Because the article wasn't comparing F# to imperative languages. It was comparing it to other functional languages and asking why F# is unpopular among functional programmers.
I think most people prefer imperative languages, even after they've learned about functional programming. The simple evidence that I see is that functional programming has been around for a long, long time and it never took off except for in certain niche circles and academia.
Do you prefer functional programming or not? It sounds like you do (or at least very open to it) although you didn't learn Scheme first... So why does everybody else have to learn Scheme first in order to reach the same conclusion as you?
I don't think it's true. I didn't learn SQL first and now I prefer that DSL for a whole host of problems. People aren't really that static.
Functional programming patterns are certainly very useful to know. However, the fact that you can apply those same patterns elsewhere seems to seems to negate the need for switching to purely FP languages because you gain next to nothing and you lose almost everything.
My understanding is that it's more of a multi-paradigm language; more like Scala than Haskell. And it's very apparent that modern C# itself has been influenced by FP concepts a lot (in compare to Java, for instance). You don't need to be a "noisy fan" to see the benefits of the functional approach.
- F# replaced C++ on the black sheep role from Microsoft languages list, usually missing from their documentation when they list available languages (.NET Native and .NET Core are two examples)
- Lack of GUI tooling forcing any desktop developer to use a mix of C#, VB.NET, C++/CX for the UI + F#, or load XAML files by hand via type providers
- It is easier to gain adaptation at the enterprise level with multi-paradigm languages and existing ones are getting good enough support for FP algorithms, even if it is not clean approach. I rather have this than no FP at all.
- Many enterprise developers and their managers are still quite vocal against type inference and LINQ in C#, VB.NET, let alone allow something like F# on their codebases
- Since F# got type providers, many presentations try to sell the language to C# devs based just on this feature, which doesn't matter at all for the typical ETL and CRUD enterprise applications
They actually explicitly used to say...do your UI in VB or C# and your compute intensive work in F#. F# just wasn't their focus. They were productivity language/tooling focused.
I haven't heard anyone against type inference. Not saying that it doesn't happen. Every place has it's weird "thing"...just haven't seen it personally.
I guess I'm saying that I don't think it was some kind of conspiracy or anything. I just think that there focus was/is elsewhere.
var is not the same as Variant. var is merely a placeholder for the real type, which the compiler infers from the RHS expression type. Variant is closer to object than var.
EDIT: It turns out the parent and I agree 100%. Darn double negatives! :)
Ironically, being strictly against something looks like you know what you are doing. We should promote this guy, he prevents alot of bad things happening.
This is how I've had my ReSharper code formatting rules set up for years. I only use var when the type name explicitly appears on the RHS of the equal sign (e.g., in an explicit cast, a generic type parameter, a constructor, etc.)
var is an excellent way to reduce redundancy in an assignment expression; it helps avoid stuff like:
Dictionary<int, List<CustomClass>> dictionary = new Dictionary<int, List<CustomClass>>();
The more widely held view is that var should be used as much as possible, as you can see in Resharper defaults. You needn't care about the types, if the compiler handles it for you. Code like int sum = getSum() needn't break if the getSum() implementation switched to using longs. There will be exceptions, of course.
People get by with dynamic types. Much better with structural types. You're having full nominal typing and using LHS declaration for documentation. Which if ever needed (typically you shouldn't), hovering over it gives you anyway.
I generally like var, however one thing I've found to bite me in the ass occasionally is using var for results returned from asynchronous operations... and then forgetting to use await on it :)
It doesn't completely solve the problem, but if you set CS1998 to be a compile time error rather than a warning it will help. This means methods marked "async" must have at least one "await".
From my experience it takes only 2-3 weeks for a C# developer to start writing F# code in the same imperative style as he/she used to in C#. That's the beauty of non-pure functional (aka functional-first) languages like F# and OCaml -- you can start writing imperative code and then gradually introduce functional patterns as you learn them.
I have found this to be true. All my developers can at least program some F#. Some are better than others, but all can do it. Before I started, no one on the team knew F# and were a little hesitant to use it. Even the majority of the interns I had programmed it too. The biggest problem with adoption is fear / apathy.
The guy that writes Mechanical Sympathy, Martin Thompson, has said that people who think pure functional programming are the future are missing the point that hardware favors the imperative model. He's worth a listen to. Many talks on YouTube.
I'm guessing it is easier to optimize via imperative way than functional. Although you can optimize functional libs up to a point, I say that people with enough time and dedication will probably optimize better with imperative paradigm.
OTOH not a lot of projects require uber optimizations.
The issue is that imperative algorithms and data structures are easier to optimize for hardware regarding cache sizes, memory access patterns and memory reuse.
Whereas this is also possible in FP languages, but since they tend to abstract the hardware, it requires support from "clever" compilers.
I don't fully agree with him, given the previous experience with the Connection Machine and *Lisp, but as usual in computing, unless one doesn't implement something and prove it with benchmarks, it doesn't happen.
Actually, that was one of his major points in the lecture that I referenced. Basically, you should start with measurements and go from there. He said that he personally uses FP quite a bit, so he wasn't a hater per se...except for FP fan boys. He did go on about that quite a bit.
The main thing that he stressed about data structures was that memory layout matters in that hardware has a lot of built in intelligence for accelerating memory access patterns that it can discern. The way that immutable data structures are created, updated, and destroyed don't produce a suitably detectable memory access pattern, apparently. His explanation was detailed and is worth watching. That being said he wasn't proposing "share state for all". He was mainly proposing the scientific method.
He is writing that statement from a perspective of engineer of high performance / low latency systems. If one uses that argument while developing N-tier "enterprise" application with huge ORM, DI and web framework on top of it... that's missing a point.
A common argument for functional programming is that it's inherently better suited to parallel hardware [1]. So if you buy this, and agree that future hardware is likely to emphasize more cores over faster ones, you have an argument for functional programming being the way of the future.
Of course, this argument has been made at least since the 80s...
Like I said, his talk is worth watching. he makes some detailed arguments to back his case. He spends a large part of the talk going over concurrency myths that he's encountered over the years.
And even with all of that, his main point was that you should use the scientific method and make measurements and adjust your approach based on those measurements.
C# was painstakingly designed to be palatable by large hoards of programmers, most of which used C++ and Java at the time. With stuff like out and ref parameters, the unsafe keyword, a C++-like class syntax (even with things that look like destructors), it was obviously an important goal to appeal to C++ programmers more than Java could.
F#, on the other hand, doesn't look familiar at all to anybody but experienced functional programmers. This matters, because as a language you don't get a lot of time to seduce programmers. Most of us use the first code snippet we see as a way to determine whether to keep reading or close the tab.
That, or the language really needs to offer something special to keep us reading. PHP's advantage was "just upload some files over FTP and it works, no need to learn that complicated unixy cgi-bin stuff". Elixir/Erlang/go have "super high concurrency without the headaches". None of F#'s many cool features have the same "ok, now you got my attention, I need this, now" aspect.
These days there's a wider variety of syntaxes that a common. Ruby, JavaScript and Python became popular, also more popular than they were when F# first appeared. I suspect the syntax will feel less strange to many people. Maybe things are going to change.
I actually think it's catch-22 with popularity as well as being a bit niché.
* When choosing language/platform for enterprise projects (where .Net is most commonly used) the company will go with one where they can find/have talent and resources. There's not many F# developers out there so you're severely limiting yourself.
* Since C# is more popular and has better tooling there has to be a substantial advantage of using F# instead. From what I can see that may only happen in certain financial and engineering solutions where minimizing the risk of errors, unit conversions, calculations etc is severe (Lose a couple of million dollars/Challenger-explosion -severe). Those projects are pretty far between ,and in some of them you can simply make do with c#. Another problem might some of those kinda of projects are usually not done in .Net to begin with.
It seems that F# is very nice for projects that are more based around calculations and formulas, but that's not enough for it to gain critical mass. Also C# has been encroaching on F# by becoming more functional with things like LINQ, lambdas etc. The type system is worse (C# main weakness right now), but still.
I'm no F# expert though so feel free to correct me
As someone who keeps hearing about F# but has not used it, I look at C#'s evolution - generally speaking, the language just keeps getting more and more terse for the common use cases (without sacrificing readability), especially in line of business applications. Combine it with a tool like Resharper, and generally, coding in C# is quite a pleasure.
Also, it is not as if C# is stagnant - e.g. the introduction of async and await keywords.
It seems as if people promoting F# try to create use cases which are, frankly, not very often seen in the domains where C# is commonly used. Maybe I am completely mistaken, but F# seems to lack a so called "killer app" use case where people notice and say "aha! That's why you need it".
As someone who writes in C# and F# I can say the absence of nulls in F# alone makes it worth switching. Typically if something compiles in F# then it works reliably - a huge time/money saver.
I'm working on a big c# app right now. All over the code base are areas where we always assumed a call to .first() would always return at least one thing. The business needs have changed and now we have use cases where we return nothing. I've been playing a game of hunting down the many little areas where this could crop up.
I can imagine that in f# this refactor would be a lot simpler and would allow me to have a case of empty that I could propagate around and handle transparently.
In C#, null is just one possible value of the regular type Foo. The compiler cannot tell whether you have started returning null where you previously only returned non-null values, nor can it tell whether you've handled those null values correctly at the consumption site.
In F#, None is a subtype of the Option<Foo> union type, which is different from the plain Foo type and from the other subtype Some Foo. If you change a function that used to return a plain Foo into one returning Option<Foo>, every place in your code where that function is consumed will throw a compile error until you edit it to unwrap and handle the distinct Some Foo and None subtypes.
Many functional programming languages have stronger type systems than C#. They typically don't accept null as a valid substitute for any type. To represent a nullable type, you wrap the value in a generic container. Think of it as being like an array that contains at most 1 item.
The interface of this generic container only allows you to interact with the (potentially) wrapped value in a way that is type safe. That doesn't completely eliminate having to think about how the business logic should differ for missing values, but it ensures that you'll never get a null pointer exception.
There is no way (from a type perspective) to guarantee in C# that an instance of a class can never be null -- this has to be ensured by code logic, conventions, etc. As application gets bigger it becomes easy to overlook a case that leads to a null reference exception.
The type system in F# can guarantee that an instance of a class can never be null and you can always refer to it safely.
I've mentioned this before, but it's worth mentioning again: unfortunately, F# is not guaranteed to be null-less. As soon as you are working with instances of some class (for example string), you are back to normal null checking. Of course you can wrap the string in an option, but it can still have a value which is null... So even if you don't have any kind of interop, you can still end up with NREs. So what you'll have to do is tell your teammates to not use nulls, and instead make proper use of option etc, and then you're back to avoiding NREs by conventions, not by the compiler helping you out. Am I incorrect in this?
F# seems like a very nice language, but honestly, C# is getting so much love from Microsoft that I haven't felt motivated to learn F# properly (the situation is very different in Java land). Seems like non-nullable references may even make it into C#, so there you go! :)
> So what you'll have to do is tell your teammates to not use nulls, and instead make proper use of option etc, and then you're back to avoiding NREs by conventions, not by the compiler helping you out. Am I incorrect in this?
You're not wrong, but I think you're being too rigid. Type safety isn't a yes or no, it's a sliding scale between mathematically-guaranteed correctness at compile time and unsafe user convention, and on that scale F# is definitely to the left of C# - although it's to the right of Haskell and dependently-typed langs - because while it doesn't provide full safety, it still make safe code easier to write (the famous "pit of success").
Sure, F# lets you write "null" instead of "None" if you want. But C# lets you write, e.g., "dynamic" - does that mean C# lacks static typing and "avoids MissingMemberExceptions by convention"? Of course not; you have to go out of your way to use dynamic, because the language provides you with static types and encourages you to use them. Likewise, F# provides you with the Option type and encourages you to use it - you have to go out of your way to use null in its stead.
A F# coworker that used null would be committing an obvious code review faux pas, much like a C# coworker that insisted on using dynamic duck typing instead of interfaces.
(Whereas "null" is generally not considered a code smell in C#... and note that it's entirely possible and not at all difficult to implement a safe Option type in C#! It's just neither idiomatic nor popular.)
Another example is casting. In weaker languages, casting is implicit and dangerously uncontrollable. C# does better: you must explicitly cast types, but it's up to you to make sure it's a safe cast. And F# goes a tiny bit further: you have separate operators for safe upcasts and unsafe downcasts, and using the former on an unsafe cast won't compile. It's not 100% safety, but it's still better.
I agree with you, and yes, F# does help you write safer code. My main objection is with people claiming that NREs cannot happen in F#, which is simply incorrect - it sure happened to me when I was learning some F# and tried some interop (and you're not going out of your way in doing interop, using some external library or what have you). Which is fine I guess, but I think it's important to be clear about the benefits of the language when recommending it.
I tried playing around with it for a little while. I had trouble dealing with functional in the .NET world. That's purely on me. However, I tried writing a WPF app and the scaffolding required was a bit absurd. Then I tried writing a web service. A LOT less scaffolding and I did get me off the ground a bit.
However, trying to apply some existing things were slightly confusing. I had trouble understanding immutability with the existing C# structures and wasn't sure if anything I was doing in this was correct. My Google-Fu was a bit weak.
What I found strange was that I wasn't able to create a Folder in Visual Studio. I'm not sure if that was a design choice, but I decided that if Microsoft wasn't going to take this language seriously. Then I wouldn't either.
One thing I don't see mentioned - C# allows you to write pretty functional stuff. The Action and Func objects allow me to do a lot of what I would normally want a true FP language to offer, and most of the rest can be accomplished by convention.
"It has killer tooling — some of the best in the business "
Some important things are missing compared to C#. I can't use F# in the immediate window in Visual Studio, so if I set a breakpoint I have to use C# to interact with the program, which is extremely weird and impractical.
I like F# much (and hate any C-like language as the plague!) but let's not mislead ourselves. F# have inferior tooling, is worse for database development, type inference is crazy sometimes and is hard to build the same kind of generic solution as with C# or similar languages.
I use it only on osx and is even less good. Still stick with it because I see the potential and the time-savings in other aspects, but after years on OOP-Imperative have take a long time to get there...
80 comments
[ 4.4 ms ] story [ 139 ms ] threadThis is probably because imperative languages are the majority, so there's no need to soapbox, rather than anything related to the communities or the merits involved.
Note that a lot of people with "preferences" set on imperative languages have simply never stepped out of this paradigm and tried something else.
I don't think it's symmetrical - I'd bet there's more C# programmers who've never dabbled in F#, or even heard of it, than the other way round : )
Take a look at the craziest comments in a Go thread and "noisy fans" seems a little generous.
2. I didn't say noisy fans don't exist, only that it's unfair to automatically lump people with preference for functional approach into this category
And that seems to be sufficient cause for the FP enthusiasts to lose their shit in Go threads.
That sort of thing is the only exposure many of us have to FP people, for better or worse. When they pop in to tell everybody they're doing it wrong in the craziest fashion possible.
It's funny how SQL is a declarative set-language, very different from imperative and other paradigms, yet nobody seems to bat an eye about it having its proper place and role.
Functional programming is like alien to them because it may not be entirely obvious what the instructions are doing at first glance.
Despite being taught functional programming, I didn't get it until I learned Clojure.
If my first language had been a Scheme instead of Basic / Java I probably would have preferred functional languages.
Now functional languages are another tool in my belt, and I frequently apply their patterns when I'm in more imperative languages.
Do you prefer functional programming or not? It sounds like you do (or at least very open to it) although you didn't learn Scheme first... So why does everybody else have to learn Scheme first in order to reach the same conclusion as you?
I don't think it's true. I didn't learn SQL first and now I prefer that DSL for a whole host of problems. People aren't really that static.
Functional programming patterns are certainly very useful to know. However, the fact that you can apply those same patterns elsewhere seems to seems to negate the need for switching to purely FP languages because you gain next to nothing and you lose almost everything.
- F# replaced C++ on the black sheep role from Microsoft languages list, usually missing from their documentation when they list available languages (.NET Native and .NET Core are two examples)
- Lack of GUI tooling forcing any desktop developer to use a mix of C#, VB.NET, C++/CX for the UI + F#, or load XAML files by hand via type providers
- It is easier to gain adaptation at the enterprise level with multi-paradigm languages and existing ones are getting good enough support for FP algorithms, even if it is not clean approach. I rather have this than no FP at all.
- Many enterprise developers and their managers are still quite vocal against type inference and LINQ in C#, VB.NET, let alone allow something like F# on their codebases
- Since F# got type providers, many presentations try to sell the language to C# devs based just on this feature, which doesn't matter at all for the typical ETL and CRUD enterprise applications
I haven't heard anyone against type inference. Not saying that it doesn't happen. Every place has it's weird "thing"...just haven't seen it personally.
I guess I'm saying that I don't think it was some kind of conspiracy or anything. I just think that there focus was/is elsewhere.
I have seen C# style guides that forbid var.
EDIT: It turns out the parent and I agree 100%. Darn double negatives! :)
To quote the GP:
> Not saying that it doesn't happen. Every place has its weird "thing"
var is an excellent way to reduce redundancy in an assignment expression; it helps avoid stuff like:
Basically if I know what the type is by looking at that line of code, I will use var. If I don't, I won't.
People get by with dynamic types. Much better with structural types. You're having full nominal typing and using LHS declaration for documentation. Which if ever needed (typically you shouldn't), hovering over it gives you anyway.
I personally start with min noise and add stuff (accessibility, explicit types, this, LINQ query syntax) based on the team.
The only hard standard is braces: I like terse but too often you then get massive unreadable blocks.
- It's very easy to hire / train C# developers. Finding someone with a decent amount of F# experience is much more rare, at least in my area.
I highly, highly doubt this.
OTOH not a lot of projects require uber optimizations.
Whereas this is also possible in FP languages, but since they tend to abstract the hardware, it requires support from "clever" compilers.
I don't fully agree with him, given the previous experience with the Connection Machine and *Lisp, but as usual in computing, unless one doesn't implement something and prove it with benchmarks, it doesn't happen.
https://en.wikipedia.org/wiki/Connection_Machine
The main thing that he stressed about data structures was that memory layout matters in that hardware has a lot of built in intelligence for accelerating memory access patterns that it can discern. The way that immutable data structures are created, updated, and destroyed don't produce a suitably detectable memory access pattern, apparently. His explanation was detailed and is worth watching. That being said he wasn't proposing "share state for all". He was mainly proposing the scientific method.
Of course, this argument has been made at least since the 80s...
[1] http://programmers.stackexchange.com/questions/293851/what-i...
And even with all of that, his main point was that you should use the scientific method and make measurements and adjust your approach based on those measurements.
It's on here somewhere:
https://www.infoq.com/author/Martin-Thompson
C# was painstakingly designed to be palatable by large hoards of programmers, most of which used C++ and Java at the time. With stuff like out and ref parameters, the unsafe keyword, a C++-like class syntax (even with things that look like destructors), it was obviously an important goal to appeal to C++ programmers more than Java could.
F#, on the other hand, doesn't look familiar at all to anybody but experienced functional programmers. This matters, because as a language you don't get a lot of time to seduce programmers. Most of us use the first code snippet we see as a way to determine whether to keep reading or close the tab.
That, or the language really needs to offer something special to keep us reading. PHP's advantage was "just upload some files over FTP and it works, no need to learn that complicated unixy cgi-bin stuff". Elixir/Erlang/go have "super high concurrency without the headaches". None of F#'s many cool features have the same "ok, now you got my attention, I need this, now" aspect.
These days there's a wider variety of syntaxes that a common. Ruby, JavaScript and Python became popular, also more popular than they were when F# first appeared. I suspect the syntax will feel less strange to many people. Maybe things are going to change.
* When choosing language/platform for enterprise projects (where .Net is most commonly used) the company will go with one where they can find/have talent and resources. There's not many F# developers out there so you're severely limiting yourself.
* Since C# is more popular and has better tooling there has to be a substantial advantage of using F# instead. From what I can see that may only happen in certain financial and engineering solutions where minimizing the risk of errors, unit conversions, calculations etc is severe (Lose a couple of million dollars/Challenger-explosion -severe). Those projects are pretty far between ,and in some of them you can simply make do with c#. Another problem might some of those kinda of projects are usually not done in .Net to begin with.
It seems that F# is very nice for projects that are more based around calculations and formulas, but that's not enough for it to gain critical mass. Also C# has been encroaching on F# by becoming more functional with things like LINQ, lambdas etc. The type system is worse (C# main weakness right now), but still.
I'm no F# expert though so feel free to correct me
Also, it is not as if C# is stagnant - e.g. the introduction of async and await keywords.
It seems as if people promoting F# try to create use cases which are, frankly, not very often seen in the domains where C# is commonly used. Maybe I am completely mistaken, but F# seems to lack a so called "killer app" use case where people notice and say "aha! That's why you need it".
I can imagine that in f# this refactor would be a lot simpler and would allow me to have a case of empty that I could propagate around and handle transparently.
In F#, None is a subtype of the Option<Foo> union type, which is different from the plain Foo type and from the other subtype Some Foo. If you change a function that used to return a plain Foo into one returning Option<Foo>, every place in your code where that function is consumed will throw a compile error until you edit it to unwrap and handle the distinct Some Foo and None subtypes.
The interface of this generic container only allows you to interact with the (potentially) wrapped value in a way that is type safe. That doesn't completely eliminate having to think about how the business logic should differ for missing values, but it ensures that you'll never get a null pointer exception.
The type system in F# can guarantee that an instance of a class can never be null and you can always refer to it safely.
F# seems like a very nice language, but honestly, C# is getting so much love from Microsoft that I haven't felt motivated to learn F# properly (the situation is very different in Java land). Seems like non-nullable references may even make it into C#, so there you go! :)
You're not wrong, but I think you're being too rigid. Type safety isn't a yes or no, it's a sliding scale between mathematically-guaranteed correctness at compile time and unsafe user convention, and on that scale F# is definitely to the left of C# - although it's to the right of Haskell and dependently-typed langs - because while it doesn't provide full safety, it still make safe code easier to write (the famous "pit of success").
Sure, F# lets you write "null" instead of "None" if you want. But C# lets you write, e.g., "dynamic" - does that mean C# lacks static typing and "avoids MissingMemberExceptions by convention"? Of course not; you have to go out of your way to use dynamic, because the language provides you with static types and encourages you to use them. Likewise, F# provides you with the Option type and encourages you to use it - you have to go out of your way to use null in its stead.
A F# coworker that used null would be committing an obvious code review faux pas, much like a C# coworker that insisted on using dynamic duck typing instead of interfaces.
(Whereas "null" is generally not considered a code smell in C#... and note that it's entirely possible and not at all difficult to implement a safe Option type in C#! It's just neither idiomatic nor popular.)
Another example is casting. In weaker languages, casting is implicit and dangerously uncontrollable. C# does better: you must explicitly cast types, but it's up to you to make sure it's a safe cast. And F# goes a tiny bit further: you have separate operators for safe upcasts and unsafe downcasts, and using the former on an unsafe cast won't compile. It's not 100% safety, but it's still better.
The author alludes so too: "C# is good enough for most".
1) F# team prefers an ivory tower of pure language design to making killer _new_ products like Akka.
2) Meaningful whitespace is a matter of taste and not some golden standard. I like my languages with punctuation marks in them, thanks very much.
3) Total global inference and ultimate succinctness is a matter of taste and not some achievement. I don't program in Brainfuck and ML.
However, trying to apply some existing things were slightly confusing. I had trouble understanding immutability with the existing C# structures and wasn't sure if anything I was doing in this was correct. My Google-Fu was a bit weak.
What I found strange was that I wasn't able to create a Folder in Visual Studio. I'm not sure if that was a design choice, but I decided that if Microsoft wasn't going to take this language seriously. Then I wouldn't either.
Some important things are missing compared to C#. I can't use F# in the immediate window in Visual Studio, so if I set a breakpoint I have to use C# to interact with the program, which is extremely weird and impractical.
F# is a _fantastic_ language though.
I use it only on osx and is even less good. Still stick with it because I see the potential and the time-savings in other aspects, but after years on OOP-Imperative have take a long time to get there...