220 comments

[ 1.9 ms ] story [ 258 ms ] thread
Unfortunately, fixed width and centered code sample doesn't render nicely on mobile devices, so the argument fails to convince me (otoh, I've read good things about F# elsewhere, so I was already intrigued).
There are lots of great languages out there -- "the best" will always be hyperbole -- but F# is a really good one. Strong library support, cross-platform, interoperability with C#, a type system that helps rather than hindering you. If you want or need to target .NET, F# is the place to be.
I’ve been loving F# for all those same reasons. I started out with OCaml, but the lack of a wide ecosystem of readymade stuff really made it hard to pick it up for projects. The dotnet world is probably second only to the JVM world in terms of ecosystem, and Giraffe is a lovely micro framework that beats most frameworks I found for Scala.
(comment deleted)
Best Programming languages today

F# - ML + .Net

Clojure - Java + jvm + lisp

Rust/OCaml - System Programming

Both F# and Clojure give you access to probably the two biggest ecosystems, but they are obviously put them at opposite ends of the programming paradigms spectrum, but this makes learning both less redundant

Rust and OCaml, are probably what you should use if you want a compiled system language

Honorable mention PureScript, because haskell + Javascript (but F# will take you close and is more practical)

Well, Clojure and its dialect ClojureScript (and ClojureCLR, if Microsoft stepped up and did at least something for it) are so close, you really kind of have to consider the first two as a single group in my point of view. Many projects have a frontend written for a web browser - using ClojureScript there is very natural. You can share most utility functions between frontend and backend (in Clojure) just as we do at OrgPad. GraalVM, Babashka (based on GraalVM), libpython-clj and the Python interop and other more or less Clojure related projects (its a stretch, but Hylang?) just show the breadth of the ecosystem.

F# seems nice and if I had to pick C# or F#, I would pick F# but I see Clojure as conceptually stronger, easier to explain and teach, to finish projects quickly and run them reliably. Immutable datastructures, the REPL and somewhat related hot-code reloading on the backend and frontend also really is something. (I know, F# has a "REPL" but is it more a Shell or a REPL e.g. running even in production?) Perhaps I should update my views about F# sometime. With my current knowledge I see it as somewhat inferior to the Clojure/ ClojureScript duo and the related ecosystem.

The obvious answer why F# wins over Clojure in many people's books is static typing.
I haven't felt the need for static typing in Clojure at all. I don't understand, why people are so dogmatic about static typing. In my experience and other on the team share it too, static types really haven't (or wouldn't have) prevented any bugs. What is more important are good names for variables/ references/ functions, code that just speaks to you or is at least sufficiently clear, up-to-date and clear documentation with examples and links if needed and efficient testing/ sensible test coverage. If I really need to know the type of something, I can always use (type <something>) or more concrete e.g (string? <something>) if I want to use that information for something. If I don't know, how to use the function, I have to improve the name, the documentation and my understanding of the code perhaps. If I pass garbage to a clearly named function, I get garbage out as with the static type system. In both cases, I have to investigate and ask myself tough questions about how I understand code or whether our code-base is well maintained.

I can see static typing helping e.g. with compilers, low level software where every clock cycle and byte matter and some specialized stuff. I don't see much point in static typing in a language like Clojure.

> I don't understand, why people are so dogmatic about static typing.

Most static typing folks have backgrounds in dynamically typed languages, and it's this experience (not dogma) that informs their preferences. The inverse (people have extensive experience with statically typed languages but developed a strong preference for dynamically typed languages) seems far rarer, at least nowadays where the canonical statically typed language is not C++.

Personally, I think one of the killer features of statically typed languages is that they make it difficult for people to write code for which the types would be very convoluted. In other words, statically typed languages provide rails which guide poor developers toward better habits (and incidentally, these same rails make it very painful to port a lot of JavaScript to TypeScript or for many JavaScript/Python developers to use statically typed languages).

From my understanding, the lisp language communities tend to select for programmers who have good habits already so they probably don't benefit from this property as much as other dynamic languages. Similarly, lisp programmers can use metaprogramming without it turning into a complete shit show, which is what almost invariably happens whenever Python programmers start dabbling in the metaprogramming facilities of their language.

That said, there are other advantages to static typing besides preventing classes of errors. For example, a lot of important documentation is generated and guaranteed by the type system. A perennial problem in dynamic languages including lisps is documenting the types. If you say something is a "file-like" object, what does that mean? Does the callee require that the object has a read() method, or does it also need seek(), close(), etc? And very often you don't even get "file-like object" but rather just a terse variable name (lisps are especially guilty of this, in my experience) or the documented type is outright incorrect (typically someone changed the code but didn't update the documentation). Additionally, you get a lot more powerful tooling, because the types can be reasoned about statically (which isn't to say Closure lacks powerful tooling, but rather that its tooling is powerful in spite of dynamic typing).

Well, a considerable number of people in the Clojure programming community are often people, who developed in Java or C++ for one or two decades and sometimes people how have to switch between several languages. Most that I have talked to love Clojure above all else and can see the things not contributing to the solution of the problem at hand. Static types are at the top of the list of things that contribute almost nil and cause a huge amount of development overhead everywhere. It sometimes seems in these advanced languages, static types are there so the programmer makes the job of a compiler (easier) or that you can write an academic paper, where static typing is almost a must to get it into a journal for some reason. My colleague gave a really in depth talk/ Q&A about Clojure and touched on static types at length. I think, it could be interesting for you: https://www.youtube.com/watch?v=4UoIfeb31UU
> who developed in Java or C++ for one or two decades

Right, this is exactly my point. People think these languages (especially as they were a decade or two ago) are representative of statically typed languages.

> Static types are at the top of the list of things that contribute almost nil and cause a huge amount of development overhead everywhere.

This is your dogma, not an established fact.

I'm glad you like Closure; no doubt it's a fun, useful language. It's probably even better than Java or C++ for many things. I'm only saying if you try different languages you might see that there are tradeoffs in features. You might still think Closure is the best, but you might at least understand why people appreciate static types.

I have written some Haskell and I am quite certain, it is more practical for me to use Clojure. I know other people, who did compiler research (! see my points above about academic research) who rewrote the previous more or less exploratory Clojure solution in Haskell for better performance and other positive aspects. These are all good things. I also know about Facebook, Microsoft and other big companies using Haskell to great advantage. But the compiler e.g. is not something commercially applicable it is research, they don't have or want to sell it or make it a service. I also am not sure anybody would be interested to buy it, as they never told us about any practically applicable results (e.g. better parallelized HPC code) which was kind of the point of the research. I might be mistaken though. Anyway, the lecture and the exercises where rather good and even if it was the only thing that semester, it would justify the semester at the university for me.
> I have written some Haskell and I am quite certain, it is more practical for me to use Clojure.

Certainly, but there are lots of factors beyond static types vs dynamic types. For real world projects, I might similarly use Python or JavaScript over Haskell because it will be easier to find developers, libraries, and tooling. That doesn't impugn static types, however (on the other hand, depending on the project, Haskell might be the better tool).

Indeed, the type system is a relatively small, overemphasized facet of any programming language. See my comment here for elaboration: https://news.ycombinator.com/item?id=27784762

If you're on a project every day and familiar with all the pieces, there's not a large advantage to static typing. Static typing allows people unfamiliar with the program to make changes and have a reasonably high degree of confidence that they got them right. This can be junior devs, people new to the project, you after 5 years away, or a project that's grown to the point where nobody knows all the pieces.

I'm not saying this as a die-hard static typing fan. I wrote Python for years, have written JS professionally most of my career, and spent 2 years writing Clojure professionally. I'm comfortable with dynamic languages. The Clojure codebase was the most stable I've been on (including typed languages) largely due to the senior team and excellent QA. The only problem I had with it was when business shifted from a subscription model to an a-la-carte model, which required manually reworking a LOT of maps to match the new requirements. This is considerably more painful in a dynamic language than it is in a static one.

There IS a downside to static typing in terms of verbosity. I've seen Java codebases where half the code was there basically because of the static typing. More advanced type systems do not suffer from that problem. I'm fine with OCaml / F# / Rust / Typescript.

Great points, thank you for sharing your experience.

Manual rework of maps seems like something that a good IDE or a small script should be able to automate, that is the point of Clojure being a data structure (EDN) after all - you can do stuff to the code as if it was data. Maybe there were specifics not allowing such sweeping changes, would love to hear more if you can share more about it.

I have a colleague which became 18 just a few days ago. He newer heard of Clojure(Script) or CSS before late last year and started actively learning it sometime after that. Jan is able to work on considerable amounts of code for our new landing page that will have some special interactive OrgPad embeds in it. He didn't have much difficulty navigating Clojure or our code base considering he did most of the work after school and on weekends basically as a learning exercise. Of course, he is getting solid guidance by the team. Our CTO Pavel has 20+ years of experience as a programmer/ software engineer and can do code reviews with Jan, so that helps. It also doesn't hurt that Jan is very smart, basically hand selected over multiple years by our CEO Vít who led a mathematics course for children/ teens and as such known Jan very well. Giving Jan a chance like this is basically a pilot combining normal education with practical, professional experience. Something like a very long internship on steroids :-)

I would still stress that static types are much less valuable than good variable/ function names and documentation/ clear code in my opinion and that maybe the complexity static types introduce isn't worth it overall. I also don't think, that static types as seen in e.g. Java or C# add any discernible degree of confidence - else somebody on the team would notice already. Jan didn't have problems navigating the code base even though most of the technologies, the language and the code base were completely new for him. Yes, anecdotal but I think it really is a valid and very important point.

I'm happy it's working for you well. The map changes were more in the line of changing core maps and then having to update every place they were used. IDEs are amenable to this as long as they can figure out the references. Cursive helped some but most of the work was still manual.

My point of reference between typed and untyped code is primarily with Typescript and Javascript since that's 99% of what separates the two. For what it's worth, I do have 21 years of experience and have been lead on my projects for a number of years. As the lead, I get enough benefit from the type annotations that I've told co-workers to just any type anything they can't get working immediately and I'll fix it in code review. It's enough of an overall team velocity increase and easier code reviews that it's a win.

I'm not trying to argue with your experience. Dynamic languages work fine for building products and Clojure is my favorite dynamic language by a significant margin. I'm sure I'll write more Clojure in the future. I'm just trying to explain the benefits since I had the same mindset 15 years ago and now prefer static types. I'll mention that don't particularly like C# or Java and their type systems are not expressive enough for me to prefer over dynamic language.

I agree that at large scale, types are one of the few things that keeps a project from completely falling apart (and I love lisp, but I would have a really hard time convincing my colleagues to adopt a dynamic language), but this seems counter to that:

> I've told co-workers to just any type anything they can't get working immediately and I'll fix it in code review

If you’re co-workers aren’t able to work with the types, how can they receive any benefits?

Not everyone is at a hyper growth place, but those that are would have zero luck with this pattern.

> If you’re co-workers aren’t able to work with the types, how can they receive any benefits?

There's plenty of distance between unable to work with types at all and knowing the full breadth of the TS type system. I've worked with plenty of people who weren't enthusiastic about types and this is my way of handling those objections. Even someone who doesn't know/care about types gets the IDE features from the types.

I have yet to have someone persist in sending me lots of any types past two weeks because having your work constantly corrected is embarrassing. I don't expect everybody to care about the type system past generics so if someone wants to write a basic index type instead of the more correct keyof or opts for any over figuring out a conditional intersection type, I'll take care of it in code review. I'd rather have them writing code than reading TS documentation to wrangle advanced types and people do look at the commits when they go in and learn the tricks over time.

Anecdotally, I encounter almost no bugs when writing Python code with mypy and frozen dataclasses (i.e. immutable data structures), but many, very difficult to understand bugs without them.
Reading all comments here I'm not sure what kind of typesystems you are refering to. (you mention static typesystems but the discussion seems broader than that)

They come in different forms. Some can rely heavily on inference (Typescript) and some need to be very verbose (Java)

There are structural typesystems (Typescript) and nominal typesystems (Java)

In a structural typesystem the contents of a type can be compared to another type and match, whereas in a nominal typesystem it has to be the same type id to match. The former is more dynamic than the latter.

I don't like Javas typesystem but I like Typescripts typesystem because it's more flexible and doesn't force you to be verbose (you can for example only type function arguments and let it infer the rest)

One benefit I haven't seen mentioned here is the ability to refactor code with confidence and less need for unit tests.

For example comparing Javascript to Typescript; If I change a functions argument that is used in many places, the typesystem will give me a list of other code where the function is used I need to change in order for everything to work again.

I was referring mostly to Javas nominal typesystem. Thank you for trying to make the discussion more to the point/ precise.
> In my experience and other on the team share it too, static types really haven't (or wouldn't have) prevented any bugs.

In my experience, having written Clojure professionally in three different organizations over a period of close to a decade, static typing would have helped tremendously in producing maintainable software that allowed new developers to come into a project and get up to speed quickly, and build out more features without struggling to overcome the burden of endless boilerplate and incoherent abstractions, which Clojure makes easy. Which is to say, every Clojure codebase I inherited was a mess, and the tools Clojure provides to mitigate the problems of sharing a big codebase among a team of programmers are insufficient and place a tremendous burden of manual labor on industrial programmers--especially spec, which ironically produces exactly the kind of boilerplate pain and maintenance labor that Clojure apologists blanket-accuse statically-typed languages of producing. This directly and meaningfully impacts productivity and efficiency, and of course helps amplify bug creation as well.

> If I pass garbage to a clearly named function, I get garbage out as with the static type system.

Yep, and for the most part the only way to figure out what functions receive or return in Clojure is to either read the code, or actually call them. Relying on other programmers to be consistent and coherent in their naming is not really a great long-term approach...go figure. And, note that a side effect of this is that you often don't find out until some code is in production that you are passing garbage data around. AND that's leaving aside how badly most libraries are documented--even core libraries, how type information is rarely if ever shared in library documentation, and how Clojure doesn't enforce any kind of purity on functions so that basically, any function called anywhere can be doing basically anything.

Really it's not even about not having static typing--which is not a silver bullet, and absolutely has tradeoffs--but the fact that the community seems fundamentally immature and unable to discuss software engineering topics (static typing especially) without turning it into an emotionally laden battle between tribes, vs. a comparison between different tradeoffs. Simple vs. easy indeed.

I really did enjoy the language at one point, and credit it and RH for introducing me to the world of functional programming, but at this point I doubt I'll ever write Clojure professionally again. However if I do, it will be with a team that understands its strengths and weaknesses without attachment to emotionally-driven arguments about static typing, or whatever.

Thank you for sharing your valuable experience. Please read the following lines with as much kindness in the tone as you can imagine, they might seem a bit harsh at times - nothing personal was intended.

With great power comes great responsibility. The things you describe all seem like a problem of inheriting a code base written by people without much organizational discipline ("was a mess") or working with people ("Relying on other programmers to be consistent and coherent in their naming"), that don't have a coding discipline. Such things should be caught in a code review or perhaps cleared at the design stage. How do you want to work with people, that are not able to communicate their intents clearly to a human? How do these people "talk" to the computer through their code, are they partially guessing the "correct" code? Are these programmers perhaps producing a mess independent of the codebase or language?

I am really sorry for you, it must have been hell. I know Clojure(Script) isn't the silver bullet many people make it out to be. The programmer still has to be quite competent and quite disciplined at times but Clojure can and will support you - that is my experience. I have seen my fair share of stuff, professional programmers with two decades of experience that couldn't use a profiler and would dismiss clearly debugged issues, where they initially pointed fingers at the database and the network. It is quite easy to end up in such a state of incompetence - you don't do very demanding stuff or do the same stuff all over again for 20 years and then comes the advanced problem, you are under pressure, because the deadline has slipped again for a year and you are totally lost in the reflection hell you have created. I have other similar experiences with "professional" programming. Our CTO Pavel has a number of good war stories about static types, avoiding static types and problems created by OOP (classes are types too in my book) too.

Well, some libraries could use better documentation. So could Java, Python ... libraries. The point in Clojure is, you often can just read the whole function because it is like 10 lines of code or the whole library that often isn't that long either (200 lines of code isn't that uncommon). There are core developer on Slack basically every day, so you should be able to catch them and answer questions more or less quickly. And yes, I have had my fair share of problems with libraries too, you can check on Slack if you want - so I sat myself down and have rewritten the part that I needed more in line of our code. It is more robust as it has checks specific to our use case and we have one less dependency we would only use for 10% of its code.

In general, I think Clojure is a great language. It is very powerful and can be a chalange to wield without any kind of insightful guidance. Once you have crossed the initial steps though, you will probably surpass the productivity of most other languages even in a largish team.

I think that needs the qualifier 'many (vocal) people's'. Dynamic languages continue to be exceedingly popular. The preference for static typing is I think over-represented in online discourse.

I would be very surprised if the amount of Clojure/Clojurescript out there in production isn't several times larger than the amount of F#. Not trying to start a language war but with the exception of Jet which I don't think is around any more I can't recall a single large company using F#.

That is a good point about the vocal minority and this is a valid argument. On the other hand, I wouldn't consider the amount of code that was written in a language to be an indicator of good design (that usually saves work/ lines of code) or other qualities. I find, I solve the same class of problems better with Clojure instead of e.g. C# or Java or even Python (when not some SysAdmin stuff written for and with Python in mind - basically a DSL for the specific task).
> Dynamic languages continue to be exceedingly popular. The preference for static typing is I think over-represented in online discourse.

The most popular dynamic languages are all adding static typing though. Typescript became extremely popular very quickly, Python has been adding types annotations for a long time now, Ruby is adding them too, some team at Facebook is working on the same for Erlang. I've seen a few times Clojure users saying they don't need them, and considering Clojure has immutability, a strong REP and spec, I can understand that they don't feel the need. But Python, JavaScript, Ruby and even some Erlang/Elixir users think the opposite.

> I would be very surprised if the amount of Clojure/Clojurescript out there in production isn't several times larger than the amount of F#.

I think the same, but the thing is that I think the amount of Java for web apps is already several times larger than the amount of C# for web apps, which can skew things.

Annotations/ hints you can use optionally to convey extra metadata are a very different thing compared to types you have to use else nothing will really work.

There were some optional type systems for Clojure but I cannot say how successful they are or were. I think the critical parts, e.g. APIs or code boundaries are specced out and that seems to be the recommended solution.

Btw. just that people are adding something doesn't mean that it is good or helping in general. It is great, Python has the optional type annotations precisely because they are optional - you can use them when you think you are better off doing the extra work.

> Annotations/ hints you can use optionally to convey extra metadata are a very different thing compared to types you have to use else nothing will really work.

I don't really agree. In Python for example, it's about making the implicit explicit. It's to make sure you don't use a function that only works on floats with ints. If you don't, you'll have a runtime exception, and it can be good idea to catch these errors at type checking time. You're already using types in dynamic languages, but they are implicit. Static typing makes the implicit explicit, and helps avoiding errors. If your type system is limited, it can make some things annoying that are easier in a dynamic language, I don't deny it.

> There were some optional type systems for Clojure but I cannot say how successful they are or were. I think the critical parts, e.g. APIs or code boundaries are specced out and that seems to be the recommended solution.

As I said before, I can understand that it's less necessary in Clojure than in Python or Ruby, because of things like immutability.

> Btw. just that people are adding something doesn't mean that it is good or helping in general.

It means precisely that though, if they're adding it it's because it brings value. Sure, your 50 line script probably doesn't need them, but your 10k app could benefit from them.

PHP has all kinds of annotations and conventions for enforcing type safety now.
That's true, I completely forgot about PHP. One thing I like about it is that it's included in the language and you don't need an external too like mypy to validate the types.
> The preference for static typing is I think over-represented in online discourse.

I think you're mistaken. It is my impression that the dynamic language advocates are, per person, more vocal than the static language advocates.

But as I said, that's my impression. And as you said, you think the opposite. That is, we both admit that we don't actually have data.

Anyone who does have actual data, feel free to supply it...

I also get the impression that that F# sits on top of its host VM better than Clojure, although I haven't used Clojure to any great degree. F#'s error messages are actually pretty good, and integrates with .NET so well, you really don't even need to know the existence of C# when using it.

I really wish .NET Core came earlier and would have enticed Clojure to stay as a .NET language.

ClojureCLR does support .NET (Core) but there isn't any support by Microsoft and a .NET language really need at least some support by Microsoft, to be viable at all.

Clojure work great with JVM, it is very tightly integrated. Similarly ClojureScript and JavaScript, even though that is actually transpiling. With shadow-cljs, it really is quite integrated into the ecosystem.

> I see Clojure as conceptually stronger, easier to explain and teach, to finish projects quickly and run them reliably.

First hand unfortunately I find the opposite is true - I have personally seen Clojure abandoned in a company and F# adopted instead in the same company albeit different parts. A rare case considering the nature of both langs. F#, to me really is like a statically typed Python that's got better performance, has better portable package management, and reads easier than OcAML/Haskell to newcomers with its "light" mode syntax. Having used Scala, Clojure F# feels like a simplification - it only takes in more expressiveness if it can stay simple. It also reads quite similar to most new breed lang's (e.g. for me when I look at Rust - if I squint many of the constructs look similar). In a month I've seen dynamic language only devs (e.g. JS, Ruby) with no static typing experience be productive in F# contributing advanced code - I've also seen Clojure abandoned in the same company with dev's perplexed with all the brackets, lost as the code scales, etc. Because it is simpler than Scala, Haskell, etc but does pretty much most of what these langs do (80%/20% rule) its a good gateway into functional programming IMO. With some of the new features in .NET 5 it can also be faster since it tends to run closer to the metal than Scala (i.e. no implicit wrapper types, rather use compile time polymorphism, stack allocation support, value types, etc when needed)

F# also has a REPL, and yes its simple but it does the job I argue with a lower learning curve. With one single script file you can load all dependent packages, and write your quick script straight from a naked .NET installation. Just `dotnet fsi script.fsx` or if you want to shebang the script that works too. May not be as pretty as Clojure but it has most of the bells and whistles and arguably much easier for a newbie to understand. There's also a ClojureScript like facility in Fable, heard good things but haven't used it personally. Being able to cut and paste a script in text (e.g. via Slack) to a colleague and it just works on their machine, libraries/packages restored whether they are on a Mac, Windows, Linux machine is pretty cool. All they need is .NET 5 installed.

On the teaching aspect using a JS dev (could be any lang) as an example - a module in F# is the same as a module in JS approximately - they contain functions that refer to other modules. Async blocks are similar to async/await and promises (! instead of await keyword). After that they get the hang of it pretty quickly. They even start to want to move away from their previous language as they realise things just work first time more often. They don't need to learn classes, OO, or all the frameworks typical of a C# project and all the "patterns". In other words it still feels concise like JS/Go/Ruby/etc to them. Functions chained to other functions in a readable syntax - that's it.

I've also seen F# dev's present F# code on slide decks to non technical people and it be well received - they didn't realize it was actual code. There's Twitter threads over the years on this exact scenario and it's what initially made me curious about the language. I can't imagine that happening with Clojure and its syntax of brackets, :require, classpath setup, etc etc.

F# doesn't even make the list.

Here are the top 5.

  1. Python
  2. Python
  3. Python
  4. Python
  5. Python
If you REALLY can't use Python, then Rust or Go. If you are programing a game, the GDscript.
Found the person who's never worked on an enterprise system
>Found the person who's never worked on an enterprise system

Pfft give me break. I manage the damn things for a living. I work on enterprise systems all day, everyday, just not as an application coder. I'm SysAdmin so I am in Terraform/Ansible/Jenkins/Kubernetes and, you guessed it, Python, all day.

I am the one that makes sure your shitty-ass F# application gets into production.

If you have interest, have a look at https://github.com/babashka/babashka and https://github.com/clj-python/libpython-clj

I am a System Engineer/ Administrator by heart and found the Clojure threading macro to be really close to the Bash pipeline conceptually but just way more powerful. I really wasn't enjoying programming much before - I have coded in several languages, Python being quite at the top for me and being on the ok to fun side at times even, but I really wouldn't change Clojure/ ClojureScript for any other language unless I had to. Btw. I have written my fare share of Ansible as well and lost quite a bit of hair understanding the mess that is Jinja. I wrapped some GoDaddy REST APIs using Ansible + Jinja and that really was stretching the capabilities of those tools (it works and is even quite clean, but it was much more work than it needed be). I would probably be able to implement an alternative to Ansible/ Jinja for the specific task and finish the task in the same amount of time I wrangled Ansible + Jinja which are supposed to make this kind of work easier/ save time. And Ansible really is much better than some other stuff. I think, Babashka or https://epiccastle.io/spire/ or something similar will eventually break through and hopefully improve the situation considerably but there is still much work to do.

Obviously this is subjective, but for my money I use Go for everything where development velocity matters and Rust for everything where performance and/or safety are paramount. I steer clear of VM and interpreted languages because true first-class support for statically linked native code is really hard to beat (and all of the "but you can AOT/statically-link Java/C#/etc!" promises seem to come with significant hidden caveats that you only run into after considerable investment).

Yeah, I know everyone hates on Go for its type system and because Rob Pike called it a systems language once (although the idea that OCaml is a systems language while Go isn't boggles the mind), but it's honestly so much more productive than any other language I've used. I also tried hard to like OCaml but the tooling was crumby and integrating libraries which used different standard libraries or async libraries or etc was painful. The ecosystem was also quite a lot smaller and important libraries were missing or low quality. While the Go community has its own problems, the OCaml community was positively toxic (if you have a problem for which there isn't a pat solution, then what you're trying to do is stupid and if it wasn't stupid then Jane Street would have solved it already).

While an ML type system is certainly nice to have, it turns out there are a lot of factors that matter more for practical software development, and if you're missing out on these fundamentals, the best type system in the world won't save you (and I posit that Go excels in these fundamentals even if it lacks an ML type system). I understand that this will not be a popular sentiment in a thread about F#.

I really like ML-likes, but I feel the same way about Go. I hoped for some time that a equivalent of F# would appear for Go and gain a bit of traction, as I really like algebraic data types, immutability by default and a few map/filter/reduce from time to time, but sadly that didn't happen. It's really frustrating because sum types and pattern matching would have been a good alternative to if err != nil that could be cheked by the compiler, and the language already has a more powerful switch. On the other hand, the language is nice to use, the tooling is good, and popular enough to usually have what you need.
Yep, fully agree. Unlike many MLs, Go nails syntax, tooling, runtime, ecosystem, standard library, etc but the type system could be better. In my opinion there's space for a "Rust with GC", but every time I say this the OCaml and F# people come out of the woodwork to evangelize their languages but those languages miss the mark in many important respects.
I don't fully agree about syntax. I think Go should have used the ML-style name: type. First this makes things easier to read, and second it makes things more coherant. When you declare a variable, you do either name: type = value, or name := value. This way, when you remove the type, you just fuse : and =. That's a small nitpick though. For the rest I agree.

> In my opinion there's space for a "Rust with GC", but every time I say this the OCaml and F# people come out of the woodwork to evangelize their languages but those languages miss the mark in many important respects.

I fully agree with this, Rust with a GC is what I've been looking for too. However as you said, F# and OCaml don't really fit the bill. Let's hope we can have something like that in the next 10 years!

Agreed that syntax isn't perfect (and I'd be fine with `name: type` although the current `name type` doesn't chafe me much), but it's a lot more approachable to a much wider audience (and IMO just easier to read for almost anyone regardless of background) than OCaml or Haskel or F#.

> Let's hope we can have something like that in the next 10 years!

Agreed. :)

If Google chose StandardML instead of Go, SML would win hands down in every way. Not many people or companies have tens to hundreds of millions sitting around to build a new language and ecosystem.
Not, that this matters much, probably a technicality

Dart is the language google is in a way selling, as the dev language for their new mobile platform flutter

Go, just happened, most available online material suggest that Go did really just happen

Rob pike have his taste, and build Go, in my opinion in the spirit of C, a pragmatic rather than theoretic effort

Go success, I think was not something that google really pushed for, it just happened because it seem many developer seem to prefer to use simpler languages, and deal with complexity "of using" a language, rather than learn a complex language and deal with the complexity "of learning" a language, developers are more engineers and craftsmen, rather than scientist

This is what people often regurgitates when talking about Go but I don't agree with most of it. "simple" is relative. Clojure people love to talk about simplicity too, but for some reason I imagine most of them wouldn't agree with Go programmers on what "simple" is. SML has plenty of "simple" parts too. Sum types checked by the compiler instead of having to think about "if err != nil"? That's what I call a pragmatic choice. Immutability in most cases? Again, a pragmatic choice. Option instead of checking for nil, and having the compiler do your work? Again, a pragmatic choice. If we were talking about Haskell, I would agree, Haskellers get easily excited by academic ideas. But things like algebraic data types, pattern matching and immutability are craftsmen tool. As a proof, you can see most of these ideas in Go, but they're half-formed. Returning a result and an error is a result type, but you have to do everything manually. The "switch on steroids" in Go is a half attempt at doing serious pattern matching, type switches are a proof of that. The name of the variable is here before the name of the type, but the ":" is not here.

I'm not saying we should throw everything from Go away and all start programming in SML. I'm saying that people that worked on Go were too dogmatic to include pragmatic features that would have made it a better language. You can see this easily, from Rob Pike claiming that taxonomy is the least interesting kind of science or something like that, and thus a more useful type system is unnecessary. This is dogma.

Go didn't "just happen", Go had the support of Google to write a high quality and extensive standard library, and all the tooling around it. That takes a tremendous amount of time and money. SML or OCaml doesn't have that, so it's harder for them to compete. I assure you that if Go looked like a garbage collected Rust, while still having all the great tooling, the easy concurrency, the standard library and all that good stuff, its success would have been the same if not better.

I find it's very productive to write the production code in Go, but very labor-intensive to achieve adequate test coverage over the error return branches.

Of course not every organization needs this, but many people will find B2B customers, regulators, due diligence people, etc. who are interested in the coverage metric as an indicator of quality. If you write the same tests as you would for another language, your line coverage will suck.

That’s a real bummer that anyone seriously cares about that metric, or that they think line coverage between different languages should be comparable. Insane.
Serious question: how much better is statically-compiled native code compared to a well-tested runtime like the JVM? What would make you decide to universally eschew the latter? Ease of deployment?
F# isn't really ML + .NET: the module system in F# is much less capable than that of Ocaml, but has the advantage that it is compatible with C# classes.

There's some nice stuff in F# that is entirely novel: my favourite feature is that if you omit passing ref values in a function call, they are added as multiple return values, a kind of dual to Currying.

Not so much different from SML though.
The F# module system is just as incapable compared to SML. The SML and Ocaml module systems provide higher-kinding which isn't present in F#. And if you don't have functors, you're not SML/Ocaml.
You can approach it with generics.
Depending on your definition of systems programming (there are many!) OCaml might or might not be completely unsuitable for it. Mandatory garbage collection, no real multithreading and higher than zero-cost FFI are at least reasons why it shouldn't count as a systems language.
Mirage OS seems to fit the bill.

Then there is the whole point if writing compilers should be considered systems programming.

Ocaml sold me on the value of functional languages. F# taught me that they could be practical outside of academic projects.

Ocaml's standard library is amazing, and it has a great developer community, but at the end of the day Ocaml is its own thing. F# had virtually identical syntax, but put all of .NET at my fingertips. I was using it for UDFs in SQLServer, UIs with tables and plots, and a lot more. My brief flirtation with windows ended years ago, but F# remains one of the most positive parts of that experience.

This is a reasonable article. I would like to address the part about the IDE though. All too often that discussion revolves around the advanced features of the IDE and how well it does project management. The part that's usually ignored in all that is how much overhead is involved with using a language. Not everything is a million-line enterprise banking project with 27 developers trying to integrate their work. The ability to write a program without an IDE and without configuring a project is gold. If I want to write an R script, for instance, it's nice to open a text editor and start typing. I don't need a fancy IDE or any project configuration.
Opening visual studio is harder than opening a text editor??
Yes. Reasons; Project files going back many years and many versions of VS. These files may have been "auto-upgraded" several times. Dependency changes, locations, versions, etc... Login requirements, to SQL Server, IIS, SharePoint, various cloud things. Memory requirements, old VMs on old, overloaded VM hosts. This on a team that expended a fair amount of effort to manage and improve these things. On a long enough time line, they always creep back in. This isn't really meant as a knock of VS as much as the IDE approach.
I find rich IDE features very useful for functional programming because it makes it much easier to track types via hover-over. I agree that lightweight setups are better, but being able to start a single file project with ease isn’t necessarily an indictment of IDE niceties.
Visual Studio Code + Ionide extension is much lighter weight than visual studio proper. FSX (fsharp script files) can then be written and executed directly and will cover this gap.

Technically you don't need the former, you can pipe the FSX file directly into the fsharp interactive EXE that interprets them from notepad and console if you like.

How does one actually architect a functional service, regardless of language? Is it a traditional 3 tier approach with controller, service persistence or something more... Functional?
At least in my corner of FP (Scala) my preferred functional architectures are vertically-sliced modules further decomposed into data types and algebras/interpreters. I might have an `EdgeAlgebra` and a `PersistenceAlgebra` for said module, but not always.
This sounds interesting, though I'm not quite grokking the vertically sliced modules aspect. Maybe you could explain it a bit more in detail, or link to some diagram or code repo, would be awesome.
could you perhaps expand on vertically sliced modules, what does that mean? do you have any diagram or code we can reference to get a clear idea of the concept behind the words. thanks!
We've come around to something like the "imperative shell, functional core" pattern. All the business logic is purely functional (so no database calls or side effects), and any data needs are done as close to the edge of the system as possible.

You can do it in any language, FP languages can help enforce the distinction. For going even more functional, in FP languages that support it, free monads and effect systems allow you to define interpreters for effects and you can write code more or less like you would non-functionally, but the interpretation can be pure (say hardcoded results for a query) for tests, and impure for actually running. Basically fancy dependency injection, but for everything.

When you say imperitave shell, am I correct in interpreting this shell to be the external interfaces to other systems - both incoming and outgoing eg api and dB layers? At this juncture you'd then take the data and process it in the domain core functionally? It seems like a plausible solution but it is not purely functional which leaves my question open.. How does one do it purely functional?

By going "more functional" with the free monad and effect system approach, do you mean the Result design pattern as seen in rust and F#?

If you have any working example I can dig in to that would be welcome

agreed on IS/FC. and though I've not yet had the opportunity to use "proper" effects, I've ended up writing some micro effect systems that apply to specific systems we interact with a lot. it makes testing and reasoning about the system so much saner.
You might be interested in reading Domain Driven Design Made Functional and Clean Architecture. After reading these two books I realized good application architecture shouldn't change much between functional and OO languages.

I could be wrong but I think an onion or clean architecture solves any issues you would have.

The main thing that holds me back from using F# more is that the tooling is simply not up to par. Things as basic as doing a rename refactoring automatically are not really supported, or popping out part of an expression into a temporary variable with a hotkey.

Depending on what you are used to, that might not be a huge problem, but the drop-off from the experience of working in C# or Java or even Python with modern tooling is stark.

I wish that there was an F# zealot or three working at JetBrains lobbying for better support in Resharper or Rider.

Are you not using Rider? Because all the refactor stuff you're talking about works out of the box for me in F#/Rider.
As a Haskell advocate I disagree :). But if it acts as a gateway drug I am all for it.
I haven't been in .NET for a couple of years but I've worked on quite a few .NET projects over the years. I've seen F# being added to 3 (as far as I can remember), in completely different companies/teams/contexts - and it always ended up being the same - some enthusiastic guy (or a few of them) tries to sneak in F# as a part of the system. They don't really gain traction with the rest of the team because people have shit to do and no time to study a new language at work, so it becomes "their own thing". Regularly the tooling breaks (eg. visual studio intellisense stops working on C# projects if you don't disable F# projects, builds randomly start to fail, etc.) The person who introduced it becomes the go to guy for these problems, coupled with no traction for his pet project and being a motivated developer - they leave and now the project has this magic F# part that nobody really knows how it works but everyone knows how to work around.

IMO C# is picking up a lot of small things that make it incrementally better than it was before, and at some point it's not worth the hassle to go to F#. F# features are gradually added to C# so C# developers have time to pick them up as well.

I've heard of F# only projects doing great, but I think you need to have a team committed to doing F#. Back when I was into Clojure they had this mantra of "add Clojure to your work projects as a library and pretend it's just this small thing you used to solve some problem because it's all on JVM and Java compatible and then keep expanding on it" - I think this turns out terrible in practice.

I've been that guy. & yeah, found greener pastures a couple years later

No regrets, canopy was an absolute pleasure to use https://lefthandedgoat.github.io/canopy

> No regrets

The victim of this pattern is not you

Consulting and working full time have the same problem, you need to program for the customer, not for yourself. If you work with people who are unwilling and/or unable to learn a tool, then DO NOT use that tool. It doesn't matter how much better it makes your life, you've taken a more or less functional organization and given them a bus factor of 1, where that 1 is you and clearly if you're so high on your tool you're willing to shove it down the orgs throat, you're probably looking to leave already.
Doesn’t that sort of increase your own value to the organization though as well? It would vary based on the situation but it seems like this could sort of work to your advantage if you’re the only person who can reasonably work on something critical (and others can’t be bothered to learn)
I guess, but I think that behavior falls under a dark pattern of employment.

I'm not saying you can't introduce new ideas into your organization, but this is where the politics of development comes into play. You need to get buy-in from your team and management, otherwise you're intentionally hurting your organization.

It also means when there's an outage due to X during christmas or whatever, then you're the only person who can reasonable work on it. Great work.
Only if you can ensure no one ever replaces what you wrote with their own solution.

You become critical in the short term, but also critical to the business to replace in the long term, in the same way that a vendor tripling their price often results in short term profits while customers transition off of them, leading to a long term decline in revenue.

I'd argue it increases your importance but decreases your value.

You become a single point of failure for the org, so you're more important, but you're removing value from the org because you're making it more difficult to scale the organization.

It's your bosses job to make sure there aren't single points of failures. If you try hard to become one, they might start trying hard to make you not one. You're now a bottleneck, after all.

Some places have toxic cultures so that's the norm, but if you're fortunate to be at a better place, don't force their hand to go down that route!

(There's also the aspect where if you're the only person who can do X, but now someone needs to do Y which will actually be ten times more valuable to the company than X, you've closed off that opportunity for yourself!)

I have a conscience, if I did anyone wrong, I'd regret it; the code I left behind has stood on its own
I was that guy too at one job. It was wonderful to work on a few F# projects, but I have no doubt they quickly went away after I left.
I have been on the 'receiving' end of such persons actions. We had one guy who worked probably 50% of his time on using not F#, but another "nice" thing. It never worked well and he spent an incredible amount of time patching it and fixing issues with it. I threw it out the day after and replaced it with some older boring technology, and the problems just went away.
Bravo. Yeah, I learned my lesson.
It's true that bringing in a new technology without support of your team is a bad idea. However just rejecting F# per se because C# has a lot of features is missing the point. Engineering is about trade-off and if for a given project with a given team F# is the best choice - given the information available - please go for it.
I think F# in the context of C# replacement (as a superior language) is not worth it.

If you have a team looking for a functional language on .NET it's amazing - so I don't dismiss it - it's just a very niche thing on .NET platform.

> Engineering is about trade-off and if for a given project with a given team F# is the best choice - given the information available - please go for it.

What objective measure can someone use to determine whether F# is the best choice?

Pure data-driven decisions would not be possible here, I'm afraid, because there are not enough studies about which language/framework is the more productive in a given situation (and doing such a study is super tricky, because the competences of the participants can very greatly).

What is possible however is to first analyze the core attributes of the techs which are relevant for the project and team such as: good supported libraries for the problem, support for immutable data-structure, expressiveness of the type system, experience of the team with the tech etc. You can then decide which tech fits better the environment. If still undecided you can try to build a prototype on a short period (at the risk on giving up on technologies which are hard to learn but could be rewarding on the long term).

I don’t think it matters what language people think is most productive. What really matters is what language you can hire for. In the end you have to have people to do the work.

I used to be a very big fan of a certain functional language, and invested serious time and effort into projects in that language, but hindsight tells me every single time it was a mistake. It was a mistake because if you cannot hire people to do the work then the project dies when it needs to grow.

People used to do very big projects in COBOL, which most hacker news readers have never even seen, and as someone who did some COBOL, I can confirm that it was absolutely terrible, but the projects got done and by and large with less tech stack Jenga or superfluous trash that infests so many projects today. COBOL died when the majority of people moved on, not because st80, pascal, ada and C were better, but because the industry switched to platforms where the dominant languages were day one different: pascal and C. Mac, Windows, the Unix workstations.

Maybe those platforms used other languages because they were better. Certainly I can’t imagine the Mac built with COBOL, FORTRAN, bcpl (worked for amiga, somewhat), etc. but the dynamic of leaders is different from the dynamic of followers.

I see two thinks to distinguish in your discourse. First the hiring pool. I don't see any consensus here. If you take Haskell for example there are so many talented devs knowing the language without opportunity to use it professionally that they will rush on the first job offer. Now if you take Clojure it may be different. There may be enough positions occupied to make it hard to hire. I don't know, so I'm speculating. In general a good dev should be able to pick up a new language in a few months and in my opinion the potential hiring problem may be exaggerated?

Your second point is about platforms. A FP language hosted on a popular platform has a lot to gain. That's the Clojure story. Rich Hickey tried different solutions / languages before but only Clojure was successful enough. Because it's tied to the JVM.

But... nowadays most popular FP languages are hosted on a popular platform (JS/Web, JVM, .Net) so if a FP language builts a community that is big enough (no need to be big like Python) it will be sustainable.

Last comment: if you think about sustainability on the very long term, such as COBOL projects, then choosing the default language of the platform (JavaScript for the web, Java for the JVM etc) may be wise (because the platform is more likely to die after the other languages). The truth is that most software project don't have such a long life so it should be only one criteria among other for the choice.

So to conclude given a good choice for a platform (BEAM for distributed systems for example) I think languages do matter, because they offer different trade-offs (less state bugs with FP languages for example).

>What really matters is what language you can hire for

The whole mental framework of hiring for a language comes, I think, from HR/business people assuming that programming languages are like natural languages and that language experience is a central, fixed component of a candidate's identity.

In large parts of the industry we simply don't believe this at all, interviews are about algorithms / problem solving and experience filters at senior levels are about business problem domains. Getting up to speed in whatever language is just part of onboarding.

At least part of the answer is, "more than one team member knows F#". It can't be just one person's pet language; a significant number (half?) of the team needs to be comfortable working in that language.
It can't be a small wart on the project either. If there is one small section that is inconsistent with the rest it's going to be a pain point.

I love F#, but don't think it's ideal if it's shoe horned into a C# project. You then have this boundary layer you have to maintain.

> C# is picking up a lot of small things that make it incrementally better than it was before

agree. C# is kind of morphing into F# with new features like record.

C# is Microsoft Research’s multi-decade play to convince Java programmers to become Ocaml programmers so slowly that they don’t notice.
Given that Java was Sun's attempt to bring C++ developers half way to Lisp, and C# was born out of a lawsuit due to stuff like adding Forms, COM, events and P/Invoke to Java, maybe not.
I can’t remember if it was a joke or serious, but I recall some comment on HN a while back trying to explain why Java was an ML.
C# is OO by default, F# is functional by default. Both support either but it's easier to use the tool dedicated to the style you want to program in.
I see this take a lot, and vehemently disagree.

An OO language with record types and pattern matching expressions, plus a vague hint of union types in the future; is not a functional language. Depending on who you ask, it's either a quasi-functional OO language or a bloated OO language. I used to be in the first camp, now I lean towards the latter.

Over time, projects morph into the average of their framework. If you started off badly, if it survives long enough eventually someone will refactor it into something acceptable. If you start off using FP features, eventually they will be eroded away; through friction with external dependencies, or later developers being less invested in the paradigm. In both cases you're usually left with an inconsistent codebase.

When people say that C# is morphing into F#, my usual thought is 'have you ever seen an FP project?' Take some time and read some FP codebases, and compare them with a typical C# codebase.

(side-note: one of the most widely used FP language for web development is elixir. There are a few good open-source elixir projects you can read to get a feel for the structure. Almost all elixir projects follow the same structure, and it's about as anti OO/SOLID as possible, yet still conforming to a vague onion architecture.)

The lesson:

Programming language adoption is based on politics, not technical merit.

This isn't inherently bad, but is important to remember.

Languages are successful due to the community that rises up around them, far moreso than anything inherent to the design or quality of the language itself.

Which can be correlated, but not necessarily so.

It’s not all one or another. PLs are a software product and they need proper marketing and PMF. You can describe the network effect as political but its the same kind of politics as getting your friends to change chat apps.
Why politics and not practicality? Taking a ton of time and resources (and potentially risking attrition) to migrate a thing that works to a thing that _hopefully_ works often simply doesn't make business sense. It's not a political decision (in the common usage of the word).
Practicality is a big part of the politics, but there's real politics at play as well. Different developers will have different levels of comfort with different tool chains, and different capacities to work outside their comfort zone.

This is overly reductive, but here's an example: if you have 3 developers, and 1 will be twice as productive in F# and the others will be 10% less productive, it's probably practical sense to switch, but the 2 developers will resist it, and it may fail for political reasons.

"Taking a ton of time and resources (and potentially risking attrition) to migrate a thing that works to a thing that _hopefully_ works often simply doesn't make business sense."

And yet it happens all the time. And the decision is rarely based on anything but a veneer of technical merit.

I don't think that's the lesson. The problem described is with maintainability. That's not political; that's technical. (It just looks political, because people say "No, you can't use that language" after they've seen the maintainability problem a few times.)
I've seen this pattern before: problems encountered with a new or different technology are attributed to that technology, while comparable problems with the existing system are seen as the fault of specific teams/developers or just as the sort of natural bugs you get in software development. The same kind of problem that's seen as a clear reason to avoid the less popular tool is seen as just something to solve or workaround in the more popular case.

That's how politics generally works: there always has to be a plausible "objective" reason for something, it just doesn't have to be applied uniformly or even actually true.

What you say may be true in general. But we're specifically discussing being able to hire someone to take over a code base in a language, and no, the dominant languages do not have the same problem. You can find C# programmers under any rock. F# programmers? Not so much.
The maintainability problem is a political problem, because it's hard to maintain because it's hard to find developers that know the language or are willing to invest in learning it.
That's true, but it's not entirely true.

I've seen countless migrations to React from other equally capable frameworks because "everybody uses React" it must be the best tool!

I've seen companies picking up Python because if you wanna do ML you gotta use Python, right?

Anybody can write Python, right?

Except now you have a Python codebase written by people that pretend to know Python, while they really don't know how to write a maintainable software program in any language, it just happens that Python is the only language they "know".

And now everything sucks, but at least it's trendy, right?

Programming languages are tools, if you hire someone competent in Ocaml but force them to use Java because "it's more maintainable" you now have two problems.

IMO

Yes and no, Jetbrains did an incredible job on Kotlin with seamless interop with Java, trouble-free mixed Java/Kotlin codebases, as well as reducing the learning curve and mental context switching as compared to something like Scala.

At my company there have been several devs trying to introduce Clojure as well as parallel forays to introduce Kotlin. Overall, Kotlin has caught on and spread much more rapidly and with less effort.

This is not a statement of which languages are "better" given all things equal or what problems each are suitable for, but in my first hand experience it is easier for the average Java developer to pick up Kotlin. Of course we as a company are also cognizant of the IntelliJ lock-in as I suspect using any other editor would run into the same random bugs / autocomplete annoyances that the GP experienced.

> Of course we as a company are also cognizant of the IntelliJ lock-in

There's your politics. Kotlin is succeeding because of it's ties to a very popular Java IDE, so developers already using IntelliJ tend to trust it.

It wouldn't do nearly as well without that built in base of support.

It's primarily utility, not politics. Yes, sure, Kotlin gets free press because Jetbrains and Google support it... but it's also because Kotlin is a brilliant language, it had an initial use case that was in extremely high demand (building Android apps) and JVM compatibility meant it had an enormous ecosystem of compatible packages from the start. But instead of just sitting back and riding on its initial popularity (that would be "politics"), the language has added more and more use cases (backend, multiplatform, JS), expanded its scope (kotlinx extensions), and built a following and a Kotlin-specific ecosystem of packages and tools that often surpasses the JVM equivalents in utility and quality.
The "brilliance" of any technology is not intrinsic to the technology. It's determined by humans.

It's always politics.

(comment deleted)
I see, so when I need to travel from Los Angeles to New York, deciding whether to fly on a commercial airplane or ride a bicycle, is a political decision? Reducing travel time by 99.99% isn't an intrinsic feature of airplane travel?
Would you say the 99.99% reduction in travel time is “brilliant”?

Me, I like sight seeing. A bicycle ride sounds brilliant. Even though it is much slower.

Yes, I would absolutely state that there are dozens, perhaps hundreds or thousands, of brilliant innovations, technologies and engineering feats that make it possible for a 757 to exist, and fly so safely, routinely and inexpensively that the general public takes it entirely for granted.
I’ll try make the point one last time then let you be.

“Brilliance” is a human attitude towards technology. It is not an intrinsic property of technology.

I agree that the word brilliant is an adjective that humans can choose to use or not use to describe a particular technology. Your initial statement was that making that decision is always due to politics, as opposed to a person's genuine opinion... or perhaps implying that people simply don't have the ability to evaluate something independently.
Because brilliance is about the people not about the technology it is political by definition
It actually is.

A country which would have made different political decisions may have decided to not provide a direct airplane flight, or as good of an interstate road system that makes the drive possible. They may have provided high speed rail instead that could have potentially been better if that’s what the country had chosen.

I think the fact that Google was not updating the java usable on Android might have also played a big role in kotlin adoption, don't you think?

Honestly I feel kotlin doesn't add much to modern java, and if possible I think it's generally better to use the native language to the platform. Probably a reason why kotlin is not that popular on the backend where people can use modern java :)

I think jimbokun statement is 100 percent correct which doesn't mean kotlin is a bad language.

> Honestly I feel kotlin doesn't add much to modern java

In that case, I hope you won't mind that I'll be ignoring the rest of your opinions on this particular topic.

I do not mind at all :)
Java is verbose by design while Kotlin is pragmatic. That's why I prefer Kotlin, even though on the backend I could have just as well taken the latest Java. That, and strict null checking.
Not just IDE. It's because Kotlin is a general purpose PL with wide utility and tooling which Clojure doesn't come close to. Clojure doesn't even work on mobile platforms.
I'm not a clojure dev but I don't think that's true, I think you can do react-native with clojurescript
Third party React Native bindings for clojurescript vs official Android framework apis in Kotlin are not really comparable when evaluating each language for an Android app I’d argue. But you’re right in that it is somehow possible through enough layers.
And basic similarity with Java- feels different and better, but not as different as F# from C#, or Clojure from Java.

Scala’s an interesting case, it rather did catch on.

Sure, I can see that. I was differentiating between internal company scale politics vs. larger-than-company politics. If Microsoft gave the same first-class promotion and support to F# that it did to C#, that would undoubtedly increase F# adoption.

My experience is a micro-scale observation that it did not take much campaigning to convince developers to try it (given the existing level of support backed by Jetbrains).

And if Visual Studio had level of ergonomics any closer to JetBrains IDEs....
Well, that’s because Kotlin is very trivially close to java, it’s almost just syntactic sugar over it. A language with very different semantics like clojure will of course not fit in as well.
Politics.

The similarity to Java, something many developers already know, is an appeal to current popular sentiment. You can advocate the superiority of Clojure's S-expression inspired syntax or immutably data structures or pure functions all you want, most people will just pick something close to what they already know.

Yeah, not arguing that, just wanted to point out that languages have different “activation energies” — one may be able to convince management to add some kotlin to the codebase, but it is much harder for a more exotic language.
> At my company there have been several devs trying to introduce Clojure as well as parallel forays to introduce Kotlin. Overall, Kotlin has caught on and spread much more rapidly and with less effort.

The reason might be, that Clojure is following a completely different paradigm and people are not willing enough to learn it.

> This is not a statement of which languages are "better" given all things equal or what problems each are suitable for, but in my first hand experience it is easier for the average Java developer to pick up Kotlin.

Yep, I would expect that to be the case.

There is a lot to learn for the average Java only (so far) programmer to really get Clojure.

>Programming language adoption is based on politics, not technical merit.

This is a very serious problem in a production system and it's not a political problem. Having a mixed language system is never as maintainable as a mono-language system, assuming that mono-language is up to the task.

>they leave and now the project has this magic F# part that nobody really knows how it works but everyone knows how to work around.

IMO C# is picking up a lot of small things that make it incrementally better than it was before, and at some point it's not worth the hassle to go to F#. F# features are gradually added to C# so C# developers have time to pick them up as well.

You cannot add the best features of F# to C# without making it a fundamentally different language. You're not gonna make C# into a type-inferred FP language by bolting on some random half-understood bits anymore than you can make a cat jump better by gluing rabbit legs onto it.

It's the core paradigm and philosophy that makes it great, and if anything, what I've seen hold it back from its potential is insufficient support requiring essentially importing C# idioms into the language just to interop with existing libraries.

Absolutely - F# is greater than the sum of its features. While it's good that C# keeps getting features inspired by F#, they fundamentally won't change the way it's written. The actual experience of using global type inference, immutability, sum types, currying (& partial application) and well thought out exhaustive pattern matching cannot be replicated by bolting them onto a fundamentally imperative OOP language.
The lack of sum types is the main offender that blocks any C# code is evee be even remotely close to F#.
Lack of a "unit" type is also a huge issue. e.g. need to create Task<'T> and non-generic Task, or Action<'T> and Func<'T1, 'T2> due to "Void" not being an actual type...
Meh - it's not really about "best features" or whatever. C# is getting expressive enough where it's not a pain point and it has widespread adoption and is platform default = no reason to go F# unless you're looking for a FP language.
I don't know the history of F# at Olo, but they use it in production projects and in a lot of internal tools. It has been well received, C# devs usually have no problem picking it up when needed and enjoy it. We are still ~90% C# but the F# code isn't going anywhere.
because people have shit to do and no time to study a new language at work

Which is really a positive - if you start a new effort in F#, it basically self-selects for the most technically curious or proficient devs. Most corporate C# code-slingers are fearful of learning it or putting themselves through the mindset shift required to grok basic FP principles. "Do you know or are you interested in learning F#" becomes the only interview question required. But I do agree, if you have to build a team around the "least common denominator" then pick the boring tech stack and go.

Introducing something into an existing team and starting a project or team are very different things.

But I share some of your reasoning and am curious how this actually plays out (I haven't seen any examples so far). One project I worked on, when starting they wanted to do Clojure and they ended up using RoR because everyone was using it and Clojure was a hiring concern. In retrospect RoR fell out of favour, there's a bunch of vacancies for it but it's not very hot so it's hard to find devs and they are forced to take "learn on the job" just like with Clojure, plus you need to compete with a bunch of employers looking to support their projects in now out of fashion stack. I think using Clojure would give them a unique candidate pool and be a hiring differentiator. But that's just speculation. I haven't actually seen how this choice works out in practice.

Jane Street (OCaml) and Jet.com (F#, sold to Wal-Mart) are two obvious $B examples. It seems to be more industry-dependent as well.
It worked well early on but once we ran out of F# devs to hire we regressed to the mean.
Arguably that's a "good problem to have". A startup in its early days pretty much requires all its engineers to punch above their weight class. Every company slows down/averages out as once it starts to scale.
Willingness to try a language or framework is an extremely poor selection criteria for being able to use it well or even being willing to learn how to use it well. I've seen enough shit-ass Ruby or Kotlin or Scala from people who were like "awesome, I love learning new languages!" but never got past "oh, what's the fastest hack I can find to do this in a similar way to how I'd do it in the last language I used?"
This argument 'it selects for intelligent devs' needs to die.

it just selects for people who have hipster level enthusiasm about function programming. That doesn't mean proficient.

Many talented developers have a life of their own, and can do well without changing the language.

That's why Joel said 'smart AND gets things done'.

Jesus, you described what happened in my company exactly. Now no one wants to touch that code, the build system is a constant pain, we are stuck in an old version of the tools. The way out is going to be a rewrite.
> I've heard of F# only projects doing great, but I think you need to have a team committed to doing F#.

This is very accurate, and speaks more towards the sociotechnical systems at play here than anything else. It's not just about being a fan of F# and getting management to approve you using it. You need to cultivate an environment where others want to use it too.

I'm still waiting for MS to put some real resources behind F#.
You'll just end up with telemetry in the compiler you have to download to bootstrap everything.
The main person that was really pushing it has recently left Microsoft.

He has been the best PM for F# so far.

Naturally everyone is free to change careers and all the best to him.

Now F# needs another PM with the same passion.

No justification for why F# is so good, just an assertion that it is. How about showing us some of the parts of the language which are interesting, giving examples of how it compares to other languages etc.
>>Most coders are interested in learning how to code in a purely functional manner

I didn't realize that was true. Long time coders or newbies?

I scratched my head about that too but I took it mean that functional programming concepts has its place in all paradigms and, well, I guess it still doesn't validate the statement, haha. But ya, lots of people advocate for writing OO in a functional way _when possible_. Only mutating when it's necessary or far more convenient has great benefits.
This is a bit like saying that Esperanto is the best teaching language. That may be true (I've no idea), but why invest in a language that is only spoken by 2 million people?

I've been wanting to play around with F# for years. Perhaps some day.

> ... but why invest in a language that is only spoken by 2 million people?

The classic chicken and egg problem

I don't think the metaphor holds. You don't need anyone to use F# to run F# on your server. Sure, you have the library problem, but you can easily use C# libaries, so the problem isn't as big as with something like OCaml.
Because someday you're going to want someone other than yourself to work on the code. Or, even if you don't want it, the company will.
Hiring is another problem entirely. If you need lots of people very quickly it'll be hard for F# to compete with something else, but for every other case I don't think it's so clear cut. People that use and like F# really want to work with it, and are usually more experience programmers than people that know only C#. Thus, hiring for F# makes a great filter. Considering how hard interviewing and hiring is, having another signal is a good thing.

Maybe building your startup that needs 100 new people every year on F# is a bad idea, but for enterprise projects that don't move much, it seems a reasonable choice.

Hiring isn't a problem if you want to use a language for your own project or for your own learning. Do whatever floats your boat.

Hiring (or having others on the team who can work on the code) is a problem if you want to use a language in a company. (I mean, it's not if you just want to write a one-off program. It is if you're writing a program that is going to survive for a long time and be depended on by others.)

I fail to see what problem F# solves that is not already done as well or better in Go, Rust, or Python, coupled with the wide acceptance and/or hype among other developers for those languages.
Type safety, expressiveness, consistency. Once you use an ML, it can feel like all other languages are stuck in the 70s.
I feel all one really needs is a Lisp/Scheme and an ML. Imagine if software engineering had coalesced on these two!
I really wish Standard ML had a bigger (I'd settle for active) community, a package system, and modern IDE support.

Rust feels like the closest thing to me in terms of overall practicality/ease of use.

I agree somewhat. F# is a decent language, even in some aspects "better" than Go, Rust or Python, but it is late.

I think F# does have a much stronger "in the browser" game. Yes, even a bit more than Rust, if you consider whole web applications and not just performance critical modules.

And some people and companies are extremely stuck in Dot.Net...

You are implying that people that use .net are stuck. I would say it is hands-down the best general purpose web programming language and also the goto for programming Windows apps.

Sure I can write stuff in Go or Rust or Python but I don't see that any of those offer anything significantly better than .Net, including the support level, the quality of the IDE and even, God forbid, half-decent performance.

Sure I would choose another language for something that had to be super fast or perhaps headless but otherwise I would choose .Net every time.

Disclaimer, I have professionally used Java, PHP, C, C++ and C# but not Go or Rust.

I'd really question the claim on C#/.Net being the best Web programming language. Yes, you can eek out a performance benefit over Python, but many people prefer Python and its frameworks over C#. It's also proven to be a viable road for startups.

IDEs for Python have improved a lot, and the more passionate Pythonists might fault C# for actually needing IDE tooling for being bearable...

I can see why you would prefer C# over PHP, C++ and Java for Web programming though.

> F# is a decent language, even in some aspects "better" than Go, Rust or Python, but it is late.

F# came out well before Go and Rust and well in time to compete with Python's popularity. There were other factors that affected its adoption.

None of the examples you give encourage (or even properly support) statically-typed functional programming with immutable data. The purpose of F# is to be an FP language with an emphasis on getting things done.

I think you should look again :)

Was excited to read this as I have always been somewhat intrigued by F#, but this article is missing the remaining 80% and all of its actual meat! The author talks about “oh, what really separates languages in the real world isn’t syntax but rather the development experience and job market” and then immediately shows only syntax and signs off (literally).
> Most coders are interested in learning how to code in a purely functional manner, but don't know how to do so.

Lost me. This is not true, by far.

Haha. Exactly what I thought. A lot of developers probably don't even know what it means let alone want to learn it.
What currently interests me in F# is that it has two viable options for being used in the browser - one over WASM (Bolero via Blazor) and one transpiled to JS(Fable).

It is therefor become an interesting alternative to TypeScript/Redux and Clojurescript/Reagent.

What in the world does TypeScript have to do with Redux?
At least in my opinion this combination is very common and beats many similar alternatives.

Also, Redux does make working with TypeScript slightly more difficult and verbose, at least in my experience, but I may just not be doing it correctly. The paradigm behind Redux and the Boilerplate that I end up with is what drives me to look for alternatives to Javascript and Typescript.

(comment deleted)
Every-time I see an F# post I have to share this series:

https://fsharpforfunandprofit.com/series/designing-with-type...

It's amazing

This series really helped me start understanding F#, along with some general functional programming concepts. I still have issues with certain topics, coming from a strict OOP background, but at least with C# I am able to reason about things a bit differently due to experimenting with F#.
Agreed, I'm also having a great time working through Scott Wlaschin (that linked site creator's) "Domain Modeling Made Funtional with F#" book. One of the best primers on the business process analysis/user needs gathering - development cycle I've found.
I really love Scala for all of these reasons, it also has the benefit of being used frequently in industry (big data, etc).
This article is missing so much. He keeps saying F# is the best but doesn't describe anything about the language. He discussed the criteria he was using but didn't say anything about how F# excels in these criteria.

It feels more like an introduction section than a whole article.

> If you want to personally pick up a programming language in order to become a better coder in whatever other languages you use, F# is the best overall teaching/coding language you can find.

Great, we're back to this nonsense (also promoted by Haskellers) right off the bat. The best way to learn the language you use is to learn the language you use, period. If you want to be good at C, learn frickin' C. No, F# is not going to help.

Certainly if you just want to learn about "functional programming", yes, find a relatively completist FP language that that looks easy to learn (F#, maybe - Java, nope), and you'll find it easier to learn other functional-programming languages after that. It's also a good idea to learn new programming languages in general, just to expand your career potential and also make better decisions about what to use (if and when you are ever allowed that choice...).

Actually, if you want to learn one language that will make you better at all others? Assembly. Yeah. This is not because Assembly is The Greatest Thing Ever, but because you'll understand the magic behind the curtain a lot better, and be a lot more immune to the incessant nonsensical daily hype around programming languages. For bonus points, learn to write your own compiler/interpreter (but don't feel compelled).

If there were F# implementations without .NET I would have used it a lot more.
From TFA

> If you want to personally pick up a programming language in order to become a better coder in whatever other languages you use, F# is the best overall teaching/coding language you can find.

I can't speak to F# at all, but I can to Rust, in this regard. I haven't heard many people say this before - writing F# makes you a better programmer - but mostly that F# people are GSD types of people.

In contrast, I commonly hear other people talk about how dealing with Rust's strict compiler and clippy's lints help them improve their skills by rejecting bad code. In C, C++, Python, and JS, there's limited "guardrails" so most learning or improvement is mostly self-motivated. In Rust, the guardrails are strong that many people learn a thing or two about project structure, memory allocation, performance, semver, etc.

I just feel like this claim for F# is pretty strong, when the primary argument seems to boil down to "you can change your coding style over time." Does F# have as nearly as strict and helpful compiler as Rust - or any other language built-in tooling?