13 ms·
Disadvantages of purely functional programming
- xyzzy4 10y agoI don't get why people would use functional programming for anything. It's both more difficult and slower.
- charlieflowers 10y agoWhen it comes to expressing logic in small composable, understandable pieces, nothing else can compete. Unfortunately, it does have the challenges listed in the OP, so it seems to make most sense where either (a) it is ok to leave performance on the table in the interest of clarity or (b) you create a little sandbox in which you use functional programming for clarity, and something outside your sandbox compensates for the performance cost. React and Om are examples of (b). They let you write pure functions that return the entire DOM. Then, outside that sandbox, a DOM differ makes it so you don't force the browser to re-render the entire DOM every time.
- marxama 10y agoI think it's also interesting to note that sometimes when choosing immutability as the default, which gives a slight performance penalty for basic operations compared to doing normal mutation, you end up being able to save lots of performance on a larger level. React wrappers in ClojureScript, such as Om, are a good example of this - since data is immutable, shouldComponentUpdate is automatically and trivially implemented for you, leading to oftentimes better performance than straight React. I reckon this would also be the case with the lock-free code you write in Clojure, etc.
- avmich 10y agoProgramming is both an art and a science. Art here means we don't have a hard scientific recommendations for all important cases; we have to learn tricks of the trade and use subjective judgement; naturally our programs differ widely. Art - as something subjective - also means opinions differ on difficulty and slowness. That's perhaps why downvotes - the statement like this presented as an objective fact draws enough scepticism from those who have different experience in the subject.
- norswap 10y agoFirst, functional programming is an umbrella term. This paper talks about strict FP, which is basically "no mutation", so I'll talk about that. It's clear that some other aspects of FP, such as first-order functions, closures, etc are very useful in practice. Immutability does have its advantages in that it supplies strong guarantees about what your code does. It avoids spaghetti code where everything can and does mutate everything else. Myself, I tend to use whenever its advantages outweigh its inconveniences. Immutability is especially handy at interface boundaries.
- DrJokepu 10y agoI agree that immutability is very useful, but you don't really need any kind of FP to use immutability, do you?
- 33degrees 10y agoI was going to say the same thing; it's certainly possible to write immutable object oriented code
- norswap 10y agoIndeed, it's more of a pattern.
- braythwayt 10y agoIf your data is immutable, in what sense is your code not 'Functional Programming?' "It's OO, and it can't be both OO and FP." Hmmm.
- deleted 10y ago[deleted]
- slikts 10y agoYou're confusing first-class and higher-order functions.
- GreaterFool 10y agoI use functional style in C++ with lambdas and iterators. It is nothing but slow. I use functional style in Rust. It's blazing fast. Huge body of problems can be handled by simple recursion but I've yet to see non-functional programmers use it. I don't know why. Functional style is simply better and is applicable in many languages. Modern C++ is a great example. Throw away much of OOP clunkiness, use simple functions, win! (OOP has it's place but in small quantities and with moderation). With respect to purity I'm on the sidelines. I think what's far more important is algebraic data-types, pattern matching and value-returning conditionals (values, not statements!). Rust has them and it is great and not pure.
- theseoafs 10y ago> Huge body of problems can be handled by simple recursion but I've yet to see non-functional programmers use it. I don't know why. Stack overflows.
- Mathnerd314 10y ago"Functional" languages typically have tail-call optimization and heap-allocated frames. Maybe OOP is a workaround for these missing features...
- braythwayt 10y agoWhy doesn't your language have TCO? "Nobody uses recursion." Why doesn't anybody use recursion? "No TCO."
- pmarreck 10y agoTail-call optimization eliminates those. Assuming your language provides it, and assuming you trigger it correctly. ;) http://stackoverflow.com/questions/32164370/does-elixir-infinite-recursion-ever-overflow-the-stack http://stackoverflow.com/questions/32164370/does-elixir-infi...
- rusabd 10y ago
- griffinmichl 10y agoDifficulty - Only at first. Once you get over the hump and learn to think functionally, procedural/OO starts to look like a convoluted mess. Slower - Optimize for developer time. Same reason most people write their backends in Python/Ruby instead of C++.
- sklogic 10y agoThere are cases where referential transparency is essential, so it worth tolerating all the FP issues to get there. Also, there is a lot of cases where you need a total language with all its guarantees.
- BenoitEssiambre 10y agoI rarely use FP but I certainly see it's appeal for certain things. I think the concept of immutability confuses people bit. It really clicked for me when I stopped thinking of it in terms of things not being able to change and instead in terms of every version of things having different names. Functional programming from that perspective is like version control for your variables. It makes explicit, not only which variable you are accessing but which version of it. The reason it seems like you need to copy a variable each time you modify is just to give each particular mutation a different name. Note that the compiler can optimize things. It doesn't need to keep every version in memory. If it sees that you are not going to reference a particular mutation, it might just physically overwrite it with the next mutation so that in the background "var a=i, var b=a+j", might run as something like "var b = i; b+=j";
- ThenAsNow 10y agoA significant part of my work is in a technical/numerical computing domain where Fortran is still prevalent. Most students who now enter the field have a tendency to start with Matlab, or feel like they are doing something truly modern if they use C++. For various reasons, I chose to use OCaml, and from my experience, the difficulty part is only true insofar as the learning curve goes. Once past that, FP-style problem-solving is spectacular in that the vast majority of time you spend goes not into the coding, but rather (a) thinking about what exactly your problem is, and (b) how to decompose and solve it. I can't tell you how many times in Matlab, people start writing code before they've even fleshed out (a) and (b), simply because there's so much drivel and overhead that one naturally tends to feel they're "getting things done" by jumping in and writing this code. Once I had a sufficient grasp of OCaml concepts and syntax, I would find myself getting frustrated by how little code I might get done in a day. Upon stepping back and reflecting, that was because I had not worked my way through (a) and (b), and that is where the human thinking is really required. I have since been delighted at the utility of each line of code I write and am similarly annoyed by the low signal-to-noise of something like Matlab. With respect to slower, I think my points above address "slowness" in terms of development time. In terms of runtime, it's very much a function of your choice of language/ecosystem and paradigms. If GC and typical functional overhead are a constraint in your problem domain, one can always bring over a functional style into modern languages like Rust, where performance and lack of GC are first-order design goals. But you can't tar all of FP with the label of "slow" any more than anyone can make a blanket statement that "solving matrix problems is slow". It just doesn't make sense. Lastly, as others have pointed out, Jon Harrop's points refer to purely functional styles and languages. In the end, striving for functional purity may not make sense. To illustrate, one can easily drop into an imperative style where needed in OCaml, for example when doing I/O. I use this quite a bit. But make no mistake that adopting a functional approach where it makes sense can pay dividends.
- LionessLover 10y agoI found another article linked from the one linked here more interesting, but it's not about "FP" but only about Haskell: "Why is Haskell used so little in the industry?" - http://flyingfrogblog.blogspot.de/2010/05/why-is-haskell-used-so-little-in.html http://flyingfrogblog.blogspot.de/2010/05/why-is-haskell-use... Go and grab some popcorn before you move on to the comment section... It's from 2010, I'd be interested in an update, just out of mild curiosity.
- danharaj 10y agothe company i work at, https://obsidian.systems https://obsidian.systems currently employs 10+ full-time Haskell developers. I'm not sure what the exact number is because we've been expanding lately. https://www.reddit.com/r/haskell/comments/49jjff/haskell_opportunities_at_obsidian_systems/ https://www.reddit.com/r/haskell/comments/49jjff/haskell_opp... The answer to that 2010 blog post is that the ecosystem has dramatically improved in the last 6 years.
- alecco 10y agoSorry, but that's no proof.
- tome 10y agoThe article wasn't particularly good, even in 2010 ...
- efnx 10y agoHarrop is known in the Haskell community for being a hater. Most of his remarks here are opinion, which is fine. Lots of people don't like Haskell - that's also fine, but pieces like these hurt the community because it will both push away newcomers and make industrial use more difficult. Also, I've never needed an unsorted dictionary, and parallelism is actually great in Haskell. http://chimera.labs.oreilly.com/books/1230000000929/index.html http://chimera.labs.oreilly.com/books/1230000000929/index.ht...
- striking 10y agoI like Haskell, and I use it once in a while. The thing is, I like knowing what my tools are capable of. That includes wanting to know their limits. This piece, to me, seems well-researched and factual. It's not perfect, but it's good. It has plenty of good citations for areas that aren't simply opinionated. A piece that is honest about the shortcomings of a piece of software can only help that software's community. You claim this piece will push away newcomers. As a newcomer to Haskell, I disagree. There are good things and bad things to every language. What does actually push away newcomers are the pitfalls that they're not aware of. Also, consider the fact that even though you don't need something out of a language, someone may. And those people will now know to avoid Haskell for those things they can't get.
- daxfohl 10y agoThing is, Harrop runs a business using F# and is a known troll against anything competing with F#. His MO is to focus on minutiae and make them sound like bigger deals than they actually are. Then when asked about a limitation of F# typically responds "well you'll never need that in the real world anyway". (See his responses to e.g. http://stackoverflow.com/questions/21170493/when-are-higher-kinded-types-useful/21445106 http://stackoverflow.com/questions/21170493/when-are-higher-..., trolling every single answer, including my own). So, while potentially everything in the article is true, it's all likely overinflated and/or has workarounds. I'd not put much weight on anything in here.
- striking 10y ago
- danharaj 10y agoThis post lists 9 points, but the first 7 are all variations of "mutable data structures suck in a pure language!" and the other 2 are "look at all these fucking idiots who talk about purely functional programming!" So the first 7 points are true because pure functional programming, by definition does not support mutable data structures very well. It is what it says on the tin. If you go on stack overflow you'll find no shortage of ill-informed, unhelpful input about imperative programming languages. I think it's very strange to call a social phenomenon that is universal in software that affects every language community is a disadvantage of something as broad as "purely functional programming". If you want good discussion, go on the mailing lists or the IRC channels. #haskell is a very good channel with a lot of active professionals who love answering questions. I am a professional Haskell programmer, AMA.
- skybrian 10y agoAt least point 4 seems to be about algorithms, not data structures? That is, there's nothing up front that says graph algorithms must be faster using mutable data structures, but that is apparently the case, so far.
- lmm 10y agoThere are some graph algorithms that are probably most easily expressed with a mutable, garbage-collected graph, sure. This shouldn't be something that you have to implement yourself though; if you really need a garbage-collected graph datastructure, surely you just use a library that provides one.
- danharaj 10y agoThe form of an algorithm is informed by the data structures that it uses and a data structure is informed by the algorithms that use it. Point 4 is implicitly about mutable collections.
- Mathnerd314 10y agoAny imperative algorithm / data-structure, e.g. union-find, can be implemented purely by using an IntMap for memory and a State monad, with roughly equivalent performance: https://hackage.haskell.org/package/union-find https://hackage.haskell.org/package/union-find As to whether that actually counts as "purely functional programming", I can't say. Honestly the whole term seems quite misleading. https://chadaustin.me/2015/09/haskell-is-not-a-purely-functional-language/ https://chadaustin.me/2015/09/haskell-is-not-a-purely-functi...
- GreaterFool 10y agoSadly, the author's chosen style is a rant and it is counterproductive. There's plenty of words and claims are made but benchmarks or code are nowhere to be seen. Why should anyone take these claims at face value? > Furthermore, most functional programming languages (OCaml, Haskell, Scala) are incapable of expressing a fast generic mutable hash table because they lack the killer combo of: reified generics, value types and a fast GC write barrier. Sounds plausible? Maybe. Incapable is a strong word. I'm not an expert on mutable hash-tables so I don't know for sure. If I was making a claim that you can't implement mutable hash table without 2 square feet of badger fur and a pound of whale fat would you believe me? I would like to see a citation. I have written a lot of Haskell and there was never a situation when I said to myself "if only Data.HashMap (unordered-containers) was faster". Just make sure you're using the right tool for the job (which might not be Haskell). The author doesn't seem to write any code himself but instead links to code that other people have written and then makes claims about F# being better (I can't find the F# solution to parallel quicksort from one of the linked posts). I see very little value in that.
- majewsky 10y ago> benchmarks or code are nowhere to be seen > The author [...] links to code that other people have written
- TheCoelacanth 10y agoIt's also setting a very high bar for functional languages to clear. Off the top of my head I can't even name a garbage collected language that has reified generics and value types.
- krallja 10y ago> Off the top of my head I can't even name a garbage collected language that has reified generics and value types. C#
- Mathnerd314 10y ago> there was never a situation when I said to myself "if only Data.HashMap (unordered-containers) was faster" Here's a Haskell programmer looking for a faster hashmap: https://github.com/ndmitchell/shake/issues/418 https://github.com/ndmitchell/shake/issues/418 Shake in fact does use reified generics (a.k.a. Dynamic/Typeable) and a Value type, and recommends disabling idle GC. I'm not sure if there's a "GC write barrier", Shake just uses MVar locks.
- chubot 10y agoGood points, although I agree that a lot of them boil down to similar statements. I have settled on a style of doing "functional-like" programming in Python and C++. It's more about the high level architecture than low level coding details. It means being very paranoid and rigorous about state -- but still having great tools to express it! For example: Using ZERO mutable globals, and passing state in as a parameter to functions. Using immutable/persistent data structures. These techniques are done very naturally and effectively in Python and C++. You just have to be disciplined. To me there's no real advantage to expressing something like "split a string by a delimiter" in a purely functional style. Either way, you have a trivial referentially transparent function you can reuse without causing complexity in your program. You might as well do the obvious imperative thing. However there IS a benefit to threading state explicitly throughout the application, and encapsulating it in OBJECTS (yes objects). For me, the thing that sealed the deal against functional languages for "real work" was trying to write a production quality sh parser. I went down a long path of trying to do this first in OCaml and then in Lisp. The VERY first thing that hits you over the head -- lexing -- is heavily and inherently stateful. ocamllex and ocamlyacc to me are evidence of this paucity and poverty of purely functional solutions. They're just transliterating solutions from C. Well I might as well use C then. Actually, I decided to use C++, which was like my 5th choice as language. Aside from headers and compile times, it's a good choice. I use "functions and data" (a la Rich Hickey). Except my functions and data are both CLASSES. Data objects are basically structs, except they can do things like print themselves and answer simple queries based on their values, which helps readability (e.g. 1 liners, like word.AsFuncName() ). Function objects are simply classes with configuration passed to constructors. That usually have a single method, but multiple methods are also often useful. Calling this method is basically equivalent to calling a curried function. But this is supremely useful for both compilers and servers, because often you have config/params that is constant once you reach main(), and then you have params that vary per request or per file processed. Many functions depend on both, and it's cleaner to separate the two kinds of params. So both "functions and data" are effectively and usefully implemented as classes. The key is to make some classes like functions, and some classes like data. And have more of a bipartite dependency graph, where functions depend on data, and data depends on functions. When all your classes are an equal mix of data and behavior, that's when they start getting "hard-coded" weird-shaped dependencies, and your program turns into fragile spaghetti. Functions and data are a useful architectural technique, and to me it doesn't have that much to do with Clojure or Lisp, although Hickey is certainly a great advocate.
- Roboprog 10y agoIt seems to me that yes, you need an "escape hatch" in an FP language to make your updates. It would be nice if the language required such functions, and the modules in which they reside, to be flagged. (I don't know if Haskell does something like this with mutation, or not) It also seems that an "actor model" would be a good way to encapsulate the updates in an otherwise FP program by having a loop/reduce/fold wrapped around the mutable data responding to request-events and generating responses. This allows the other pure/immutable/idempotent type of code to remain isolated from it.
- dottedmag 10y agoFlagged like "State T" in function type, which Haskell has had since ~1995?
- tome 10y agoOr IO, or ST, or STM, or any other number of Haskell features that Roboprog has correctly predicted to exist.
- dllthomas 10y agoPerformance-wise, StateT is not an escape-hatch. It can be great for removing boilerplate, but it's simply another way of writing (s -> (a, s)). IO, ST, and STM mentioned by tome better match the description of "escape hatch" - though for ST and STM they are very carefully shaped escape hatches.
- tome 10y agoLuckily Haskell supports impure functional programming too ...