I like functional programming. I think it’s going to drive code evolution through the next decade: languages will adopt more functional features, developers will adopt more functional techniques, and at some point, everyone will think that functional programming principles are the “natural” and clearest way to structure code.
But I am no longer sure of this scenario. Functional programming has a major problem that is evident to every mainstream programmer who has expressed an interest in learning what the excitement is about: Functional programmers are a bunch of smug jerks.
What are monads? “Monads are just monoids in the category of endofunctors! Ha ha, you don’t understand any of those words, do you, stupid mainstream programmer?”
What are the design patterns that help structure functional systems? “Design patterns? Hey everyone, look at the muggle try to get the wand to work!”
What does functional programming have to offer to my team of programmers developing enterprise applications that have to live in a real-world ecosystem of data, interfaces and APIs? “You don’t even see how… (long silence) If you knew category theory, you’d get it!”
Functional programmers have applied modern advances in type theory to yesterday’s Smug LISP Weenie to generate today’s Insufferable Haskell Prick. Just as LISP advocates carefully avoid the reality of decades of Scheme- and LISP-exposed CS students who happily left those languages behind, functional advocates carefully avoid acknowledging the programmers who have filed in to the functional programming room, listened to the conversation for a bit, read the literature, and quietly left.
What’s incredibly frustrating about this is that many functional programming benefits are both clear and already being used by today’s programming mainstream. Good programmers understand that immutable data is generally preferable to mutable, that functions that always return the same value for the same inputs are easier to work with than functions whose behavior depends on hidden state, and that complexity is best built with small functions that are focused on a specific purpose. And once programmers get a taste of lambda functions in combination with collection classes (the maps, flatMaps, finds and folds of the world), they won’t want to go back.
But good programmers know that insistence on any single programming technique is a sure sign of cultish over-devotion. No programming paradigm works equally well along the axes of performance, domain complexity and scale. You can have it paradigmatically pure, fast, right or big: the excellent get three choices, the good two, and a lot of teams have trouble with any one.
I recently saw a situation where a feature was vetoed from a release because it required runtime initialization: a private variable would be null until an initialization function was explicitly called. “Mutability makes things harder to reason about,” said the functional adherents, “and we don’t have time to refactor this into a properly immutable data structure.” So user value was not delivered because of slavish adherence to the paradigm. (And, to further the frustration, it was an implicit admission that technical debt was not being strategically managed.)
Such rigidity in approach can only be justified by overwhelming benefits. Indeed, extreme confidence in their own productivity is a hallmark of LISP Weenies and Insufferable Haskell Pricks. Yet a recent empirical study by Pankratius, Schmidt and Garretón that compared Java and Scala development did not reveal such triumphs. Indeed, while there were benefits (functional code performed better than expected and was more compact), the productivity results were, at best, a mixed bag. Scala programs took just as much or more programming effort to achieve the goals and were harder to debug.
As with virtually all empirical studies of software development, the sample size for the study is regrettably small and the results may be overly influenced by individual ability and knowledge. On the other hand, so what? The mainstream will evolve based on the cumulative decisions of millions of experienced object-oriented developers and many fewer experienced functional developers. Most developers aren’t going to dedicate months of effort into making the functional light bulb turn on, they’re going to make a partial effort over the course of a project or two.