1. 35
  1.  

    1. 6

      FSharp has a pretty efficient unsorted dictionary and set. Author repeatedly refers to Haskell as a performance example, and this article might better be described as “Disadvantages of Haskell”. Otherwise an okay read I guess…

      1. 9

        Author does make a good point that if all you need is speed and no safety, functional style might not fit your use case, even with the benefits of ease of parallelism.Since in theory you will be maxing out every core/computer. Nearly always however, speed and safety are cost comparisons. This means you can choose to spend money or processors or programmer time. You should always choose safety over speed if it is possible, as the work becomes more pleasant for the programmers, and processors are much cheaper than programmers.

        1. 14

          You should always choose safety over speed if it is possible, as the work becomes more pleasant for the programmers, and processors are much cheaper than programmers.

          Most of the people using C over Haskell these days are using it not because C is faster but because performance is more predictable, e.g. high-frequency trading. And I would note that for ultra-high reliability (i.e. code that goes into space) cases, C might be preferable because (a) you’re not relying on a runtime, and (b) the use of the language is so constrained, and budgets are so high relative to the amount of code generated, that correct code is achievable.

          I’d agree that Haskell achieves very high correctness and performance within a moderate time budget. (The maximum potential of C or C++ is far from relevant under the typical corporate use case, because companies will never budget the time to get software close to its max potential.) The problem there is that a language like Haskell will, simply put, never break in to corporate programming. Corporate managers don’t give a shit about technical excellence, and when they hear “Haskell”, they think, “This asshole is trying to make himself irreplaceable”. The fact is that, although enterprise-style Java achieves very poor performance [1] and takes a long time to write, it does a good job of making programmers replaceable– and that’s the only think that corporate managers actually care about.

          [1] Yes, I recognize that Java can be very performant if written by people who know what they’re doing, but the people who write PojoVibratorVisitorFactory classes don’t know the difference between the stack and the heap, and wouldn’t be able to write a correct object-pooling system, and so they will never be writing reliable or even usable Java code.

          1. 4

            Agree with all your points. As an interesting case study in where the two worlds meet, Copilot is a Haskell DSL that then compiles into C code that makes static guarantees about memory usage. It’s meant for writing embedded systems for space/aircraft, where as you said the overhead and unpredictability of GC and a runtime are out of the question.

            1. 3

              Some other examples:

              • Icicle which compiles Haskell stream processing code to C
              • Atom which compiles STM-like concurrent Haskell code to C code to run on microcontrollers
              • Clash which compiles Haskell descriptions of hardware to VHDL or Verilog
            2. 5

              it does a good job of making programmers replaceable

              I hear this very often at work. It seems like what people think is true but hasn’t been tested. I think Haskell is an extremely simple language when compared to Java (omg initialisation, overriding and private constructors, constant pools but references vs primitives, etc) - I consider myself a Java expert but put me on a random Spring Boot application and I’m totally lost for weeks. Put a Haskell programmer on a random Haskell project and they’ll be absolutely fine.

              1. 1

                I consider myself a Java expert but put me on a random Spring Boot application and I’m totally lost for weeks.

                Sometimes, I think that this is intentional. Business people would rather have an environment that brings the highly productive down, and therefore prevents the emergence of high-leverage individuals, so long as it doesn’t slow down the average people too much. Tech bosses in the corporate world win by producing reliable mediocrity, and not by unlocking individual excellence.

                Put a Haskell programmer on a random Haskell project and they’ll be absolutely fine.

                Right. There are technologies that you learn once and you have the skill for several years, and others that might seem easier to learn but have hidden traps and force you to learn what is effectively a new dialect every time you change teams.

              2. 3

                Jane Street uses OCaml over Haskell for that very reason. Still not a condemnation of functional programming, just haskell.

              3. 2

                This is true except for code that will be used a lot (repeatedly, for many years) and if your code is even slightly faster than the other code your users will save a lot of money. But, perhaps your point is that such cases are rare.

                1. [Comment removed by author]

                  1. 9

                    It’s probably not life-threatening to get wrong data out of the LHC experiments, but if you’re going to spend a ton of money to go to the trouble of collecting the data, I’d at least assign a fairly high monetary value on not screwing up the results. I.e. I’d be willing to trade fewer and slower results for a higher probability of the results actually being correct. (Formalizing precisely how, and how much, is a bit trickier.)

                    1. 5

                      Usually bugs are expensive. However I agree there are times when who gives a crap. If you’re making the next twitter, and occasionally the tweet gets thrown away, who really cares. My job history, Police/Legal software, Lab Software, and Finance Software, have biased my opinions somewhat. They are all areas where failure is very costly, and sometimes ruins lives. However if your software is so useless that nobody cares about any bugs, why did you write it?

                      1. 4

                        However I agree there are times when who gives a crap

                        I think one thing developers really need more background in is risk management. Risks need to be evaluated based on severity, frequency and number of trials. Let’s say something has a 0.001% chance of killing someone, and you’re only going to do it once- even though that’s a pretty high severity, the overall risk is very low. On the flip side, if I’m going to do the same process 1,000 times, there’s an almost certain outcome where someone dies. Which brings us to the next question: can we accept that? Is 1 death in 1,000 within our risk tolerance, or is that too high?

                        Risk mitigation is the strategies we use to control our risks- either by reducing the severity, reducing the frequency, or avoiding the risky path (thus reducing the trials), and we have to do this within our risk tolerance. Which turns into a cost-benefit problem: evaluate the risks, compare against your tolerance, estimate the costs of mitigation, and the value of performing the action.

                        1. [Comment removed by author]

                          1. 5

                            I think the important thing to remember is that, even if the chance of bugs mattering is small, our ability to know in advance whether our code will end up being important is terrible.

                            You might write a report script for a one-off problem, and see two years later that script has become mission-critical to the company, complete with an ecosystem of software relying on it. That sort of thing happens all the time, even though the majority of your one-off scripts end up getting tossed aside.

                            Bugs have impact precisely because we’re very bad judges of when to worry about bugs.

                            1. 3

                              Well, in finance there’s often one as long as you’re not entirely handing Other People’s Money, and has any firm brought low by a software bug been bailed out to the extent it didn’t sting that much?

                              Knight Capital Group (KCG) lost about $440 million on a trading glitch in 2012.

                              Worse than losing money, you can end up with your bots breaking the law, and that will definitely get you shut down.

                              Hedge funds don’t get bailed out because those people don’t have the kinds of connections that large investment banks do. The Davos people consider hedge fund managers to be nouveau riche and will let them twist in the wind. It’s people with Roman numerals in their names who went to prep schools with high-ranking Senators who get bailed out (“too big to fail”) of their fuck-ups– not upstarts who’ve been trading since they were 13 and who made a fortune by being really good at it.

                              1. 2

                                Respectfully, as a “professional” I don’t care about consequences to me, I care about the lives of the people I write software to serve. People are more real than profits.

                                However yes, often people blame themselves when they should be blaming the software and responsibility ultimately never gets back to the root cause. This is though part of why I see it as a responsibility of the programmer to watch out for real people, because we can care. While there should be some formal structure of accountability, I think we need to take it upon ourselves to do the right thing until there is.

                        2. 4

                          You mean the mutable Dictionary, which is his point. Pure functional programming imposes unnecessary performance ceilings.

                          1. 3

                            “Purely functional” is an ambiguous term, but it’s sometimes used to mean programming in a way that doesn’t permit functions to have unmanaged side effects (for whatever class of side effects you consider meaningful, which is a whole other debate), which isn’t true of FSharp and Haskell is the only real mainstream example of.

                            1. 4

                              It’s not hard at all to write FSharp in a purely functional style, and he referenced OCaml in his article which has the same “problem” , so clearly the author is aware of this.

                          2. 5

                            When I say I prefer purely functional programming, what I mean is that I prefer a language where the type system accounts for all data flow in the system. You can use a monadic interface, you can use an effect system, you can use whatever, as long as the type system is kept in the loop.

                            There is no efficient purely functional unsorted dictionary or set

                            There is no purely functional weak hash table.

                            There are no purely functional concurrent collections.

                            Most graph algorithms look worse and run much slower when written in an FP style.

                            The inertia of traditional imperative data structures and algorithms is huge.

                            These are all the same point. It’s fine to use mutable collections, but the types should reflect that you’re working with a mutable collection.

                            All existing implementations of functional programming languages, both pure and impure, happen to allocate far too much by design. […] Consequently, they all stress their garbage collectors far more than necessary.

                            It’s not that simple. When you can’t mutate data, pointers from old to new data are impossible to construct, and therefore it is easier to perform generational collection. It is also easier to perform parallel collection since you can duplicate the data in disjoint heaps and not have to worry about synchronizing changes. The best of both worlds is to track which data structures can be mutated via the type system and only perform that extra work for those data structures.

                            Purely functional programming is theoretically good for parallelism but bad for performance in practice, which is the sole purpose of parallelism.

                            It’s an active area of research, and the people interested in “purely functional” parallelism are mostly tackling this from a correctness standpoint. You can use an effect system for this too, see Deterministic Parallel Java.

                            It took 50 years for normal people to dilute the smug weenies to the point where you can get a useful answer about functional programming on social media.

                            OK.

                            1. 8

                              Just going to go down the line.

                              There is no efficient purely functional unsorted dictionary or set

                              This isn’t about language, you can use mutable vectors in a Haskell program and it’s still purely functional. Including the fragment manipulating mutable vectors. Containers usually suffices anyway.

                              There is no purely functional weak hash table.

                              I don’t know why this person keeps conflating “purely functional” and “immutable/persistent data structure”

                              There are no purely functional concurrent collections.

                              Still abusing “purely functional” but I’ll link stm-containers and point out that concurrent programming with MVars, STM, async, and unagi-chan, is a real joy.

                              Most graph algorithms look worse and run much slower when written in an FP style.

                              There is fgl which is persistent, but the trick is it makes graphs look like trees. If the perf suits you, you can use that. Otherwise, use a mutable graph impl. Nobody cares.

                              The inertia of traditional imperative data structures and algorithms is huge

                              This is getting tiresome.

                              All existing implementations of functional programming languages, both pure and impure, happen to allocate far too much by design

                              What? I can write a program that parses CSV data and uses less heap with GHC Haskell than I can with Java. (600kb peak heap use)

                              This has almost nothing to do with language semantics.

                              Purely functional programming is theoretically good for parallelism but bad for performance in practice, which is the sole purpose of parallelism.

                              ????

                              https://benchmarksgame.alioth.debian.org/u64q/haskell.html I know the benchmark is flawed, but it’s clearly competitive with Java.

                              It took 50 years for normal people to dilute the smug weenies to the point where you can get a useful answer about functional programming on social media.

                              Leaving this one uncommented upon.

                              There is a huge amount of misinformation about functional programming in circulation.

                              About that.

                              Jon Harrop

                              Oh right this bloke.

                              1. 3

                                Good article and otherwise correct but I must add that F# is getting unboxed value variations on all of its types (records, tuples, and unions).

                                1. 3

                                  What we might find out is that getting performance out of purely functional programs is equivalent to synthesis. The first I saw was conversion of formal, high-level specifications to efficient, imperative programs. The problem is turning those specs into a concrete form with the right structures and control flow out of countless possibilities. The precedent here where it was practical was hardware where some tools “synthesize” efficient representations from restricted, functional languages. That was several, NP-(hard?) problems in one.

                                  So, with the similarities, the solution for making purely, functional programs/structures efficient might be a synthesis problem that’s just as hard. Im sure heuristics can narrow the problem down like they do in hardware. Not sure how much.

                                  1. 3

                                    I’ve been arguing for FP for years but I would largely agree with the OP.

                                    First of all, few of us disagree that mutable state has a place as a performance optimization. So, perhaps “purely functional programming” is an extreme position insofar as most people recognize that mutable state within tight loops is fine. Either the language will support it (giving the programmer more control) or the compiler will translate accordingly (putting more “magic” into the machine) and there’s a trade-off either way. Most of us who fight for FP are fighting for readable code: referentially transparent functions when possible (and effusive documentation when not) and the use of small functions and procedures with definable semantics. We’re not against the use of imperative idioms (e.g. ST and IO, mutable arrays for performance optimization) by people who know what they’re doing.

                                    Second, I’m starting to realize that Haskell will never quite get into the commercial niche that we’ve been angling for. Yes, there will be trading shops that use it for batch jobs (although HFTs will continue to be written in C or assembly). You’ll see Haskell and Haskell-like languages used to prove code correct. But corporate programming (even in snobby Silicon Valley startups full of Stanford kids) is intractably mediocre and that will never change. And, so long as corporate programming is mediocre, it remains true that (a) Haskell adoption is unlikely because risk-averse mediocre CTOs fear the risk and (b) even if Haskell were shoved into these shops, you’d just get a bunch of terrible Haskell code.

                                    This is an important note, because the selling point for Haskell, to me, is that on a constrained time budget, Haskell does better on performance and correctness than other languages. Sure, you can achieve superior performance in C, and you don’t have to put trust in a runtime either… but the reality is that most corporate projects don’t have the resource budget for good (or even passably secure) C code. Haskell might be passable in that niche, insofar as it enables a good developer to achieve quite a lot within moderate time, but the decision-makers and gatekeepers in the world of corporate programming are so unfixably mediocre that (a) they will rarely grant permission for a new project to be done in Haskell “because it might be hard to hire people”, and (b) even if they do, the language (and the person who advocated it) will be the first thing blamed if anything goes wrong.

                                    Haskell is a lot of fun and it’s a great language overall, but I don’t see it replacing Java in corporate programming and driving out the mediocrity. That’s a nice dream, but it is just a dream.

                                    Of course, there are still myriad reasons why a person who isn’t doing ultra-HPC might want to use such a language. For achieving strong performance and very high correctness, within a moderate time budget (i.e. a side project) I think that Haskell is a very strong fit.

                                    1. [Comment removed by author]

                                      1. 2

                                        I like Ocaml quite a lot, but it’s been several years since I’ve used it, so my knowledge of it and its capabilities is out of date.

                                        1. [Comment removed by author]

                                          1. 6

                                            One thing that appeals to me strongly about Haskell is that it puts stateful effects into type signatures, whereas in OCaml an int -> int can still be doing IO.

                                            In practice, if you have good programmers, this is more of a non-issue.

                                            I also like type classes for their elegant presentation… but I recognize that OCaml functors can achieve the same thing and don’t rely on language extensions to work.