The best performing languages are imperative (C, C++, Rust), with functional languages being at least an order of magnitude slower both in benchmarks and real-life workloads. Whatever properties were supposed to make it faster/parallelizable have clearly not manifested themselves very well after decades.
Imperative and parallel code also does not have to be a nightmare at all, as evidenced by Rust and even Go.
Not even the most contrived benchmark games place functional languages an order of magnitude slower than C. Maybe 2-5 times slower on average. Of course, this doesn’t actually matter, because 95% of apps are performance constrained because of architectural reasons, and functional languages tend to scale better in terms of architectural asymptotics.
> Imperative and parallel code also does not have to be a nightmare at all, as evidenced by Rust and even Go.
Go is, by all accounts, a massive nightmare. I think this claim calls your judgement into question.
All accounts? That's a pretty strong claim. Go works well at Google.
Most programming tasks are undemanding, and most programmers have limited skills, so it is a good match for a great deal of routine work. It fits in the same niche as Java, where Java's OO apparatus imposes complications that are superfluous for simple applications, and an actual obstacle in most. So, a language that abandons all that is better in those applications.
Simple tools are not bad except when you need something more. So, my agreement was with the idea in mind of writing Pandoc in Go, which would be madness.
I don't know Pandoc so I'll take your word for it. I'll also agree that there are entire of classes that Go isn't sell suited for, but we'll have to disagree as to whether it's limiting for the types of applications it was created for. I must not be building the same class of application as you are.
It really comes down to whether, while working on a big system, you will discover a necessary task that a language cannot do well. This might be because it lacks a key feature, like bit twiddling operations, first-class functions, or operator overloading. It might be inherently just not fast enough to meet a deadline, or not consistently so. It might not know enough about types to prevent common mistakes, or might lack operations on types needed to direct compilation. It might lack the organizational features needed to make a large system manageable. That doesn't make it a bad language, but would make it an unwise choice for a project that might, as time unfolds, be found to need one or other such quality. Generally, the bigger a project is, the more unexpected requirements surface.
This is where we get to the idea of "dynamic range". A language with a wide dynamic range takes correspondingly long to learn. People skilled in it are harder to find and more expensive to hire, you have fewer of them ready to hand, and those you have are likely to be already busy. Yet, you might need more, and any you have more than earn their keep.
You speak the truth, functional programming languages have excellent performance characteristics when compared to other GC'd or JIT'ed languages.
I'm not sure about FP leading to better architecture, it might just be the type system there, which Rust has adapted (in a slightly less powerful form) as well.
Maybe if you had used Go to solve the sort of problem that it's meant to solve you wouldn't have judged it such a nightmare.
Mutating a value is almost always cheaper than allocating a new version of that value and collecting the old one. I think you're vastly understating the "you can usually" and overstating the "much less readable and maintainable".
Haskell is pure functional language and uses linked lists as their main list data structure. This is because it is difficult to modify individual elements in an array in a purely functional manner without copying the entire array. Meanwhile using arrays in C or Rust and changing individual elements is not only very easy, it's very fast as well.
The default string implementation in Haskell is built on a linked list of characters and it performs horribly, so Haskell has multiple string implementations. The default string implementation is still often used because it is more convenient. This is an example where writing more readable code also involves making it perform worse. Rephrased: Faster code is less readable in Haskell.
https://stackoverflow.com/questions/13865420/why-is-haskells...
Immutable data means lack of aliasing problems (two pointers to a mutable cell). There are other languages that have this property, notably Fortran. It does allow many speed optimizations, in both parallel and single-thread cases. Yes, this is one of the reasons why Fortran is routinely faster than C on numeric code, and even Haskell sometimes is, too.
It is theoretically proven that any algorithm which uses mutable data can be converted to use immutable data with a penalty on memory and time not exceeding O(log n). In absolute terms, such a penalty can be low, or pretty high (consider working with large bitmaps). There's no silver bullet.
Functional code is often preferred due to its clarity, both humans and machines have easier time reasoning about it, and even formally proving its properties. Sometimes it is just more important than raw speed, but sometimes allows for more aggressive optimizations (rewriting by the compiler) and higher speed.
I'm curious if that's really the case in practice. Functional code allows for clever concise implementations and clever concise implementations are notoriously hard to read. Go, for example, is often lauded for it's readability due to it's more verbose and non-clever nature.
edit: To clarify, I mean readability by the above-average programmer not by a world expert who has spent 15 years becoming one with the language.