There's been so many articles touting the benefits of functional programming lately. Read just a few and one theme immediately emerges: no side effects is good. With immutability there's no side effects, and with no side effects life becomes a lot easier. Programs are easier to write, compose, debug and you get concurrency for "free". While all this may be true, I feel there needs to be a little balance on the subject lest some people start to think functional programming is a silver bullet.
We live in an imperative world where there's state and things are mutable. This fact alone hints as to why functional programming cannot be the end all solution. I/O is the classic example of where imperative operations are required. For example, Haskell, a functional language, has these things called monads to do I/O. Michael Scott writes in Programming Language Pragmatics,
Monads...acknowledge that the physical world is imperative, and that a language that needs to interact with the physical world in nontrivial ways must include imperative features.
I also recall a recent article with Joe Armstrong on state and mutability in Erlang that came to the same obvious conclusion: state and side effects are necessary, we just need to confine them so the rest of the program is not polluted.
Beyond this inherent issue of modeling the imperative physical world, there are just some things that are more imperative in nature, like counting and updating. Destructive updating assignments may clog the von Neumann tube, but immutability creates a lot of garbage. The need for destructive updates leads to the so-called trivial update problem. How can we efficiently handle updates without creating new copies of the entire data structure. In imperative languages it's very easy to do map.remove("myKey") but in a functional language you have to call a function passing in the current immutable map and getting back a new immutable map with one entry removed.
There are two ways to deal with this. One is to hope your compiler can optimize. If the compiler can verify that the old map is never used after the function returns instead of creating a new copy of the map the compiler can just do the update imperatively, in-place. Apparently there's this Sisal compiler that was shown to eliminate 99-100% of all copy operations. And that was back in 1992. Then again, that was very geared toward numerical calculations, so I'm not sure how things would translate to your run of the mill web app.
Another approach is to make your data structures smarter. Smarter is probably the wrong word. The key is to recognize the difference between imperative and functional data structures. In imperative languages data structures are ephemeral, existing as-is, without a history. Think of all the data structures we use everyday in Java: HashSet, HashMap, ArrayList. They're all ephemeral. Functional languages, because of immutability, have automatically persistent data structures. Adding two elements to an initially empty list means you have three versions of the list: (), (e1), (e1 e2). In the imperative world you just have a single list of three elements.
The problem is how to achieve persistence with O(1) additional space and O(1) slowdown. Good news is really smart guys like Sleator, Tarjan and Okasaki have laid the foundation for efficient persistent data structures. I know Rich Hickey's Clojure has persistent data structures base on Okasaki's work with some modifications to get around just the amortized guarantees. A lot of the work around persistent data structures is around amortized running times, but Clojure has these "persistent vectors" so the time is guaranteed for certain data structures. While much progress has been made in this area ephemeral data structures still have quite a head start.
As someone who's basically programmed in Java all his career I find all this very functional stuff very fascinating. No doubt about functional programming's many pros, but it's also good to be aware of the cons. I remember when Java faced much criticism because creating objects was expensive, but those criticism have largely subsided. The Java language hasn't really changed, the bad programs we (I) write definitely haven't changed--it's just that the JVM has gotten a lot better at resource management. So is functional programming at a similar stage, where all that's needed is improvements in compiler optimization and better functional data structures? Or are we already there and I'm not just aware of it?