Functional programming is bigger than ever. Between Apple’s new Swift programming language, the availability of F# and Scala on the CLR and JVM respectively, and even the introduction of lambdas to Java, mainstream programmers are increasingly expected to be comfortable not just with object-oriented terminology, but with the jargon and mindset of the functional community.
There is an unfortunate mentality that divides the world into object-oriented and functional tribes. This mentality gives rise to a lie: that one must abandon the object-oriented tribe to gain the benefits of the functional tribes. If functional techniques and languages are to succeed in the mainstream (as I think they should) they must do so by evolving, not replacing, existing code. For 20 years, the mainstream has been internalizing object-oriented terminology and thought and for 20 years has been building platforms and SDKs and applications based on stateful objects. Are functional techniques helpful when working with these APIs? Can developers move between paradigms?
I think the answer to those questions is a resounding ”yes!” At a recent talk, I asked how many people in the room considered themselves functional programmers. A few hands went up. But then when I asked who had used .NET’s Language Integrated Query, many more hands went up. When I asked who had used Data Transfer Objects to decouple their data and domain layers from their view layers, hands went up. These are techniques that reflect functional thinking and they are all mainstream.
Why is there a perception, then, of a great gap between mainstream approaches and the functional community? In part, it’s that unfortunate tribal mentality (see my previous column, “Functional Programming’s Smugness Problem”) and in part it’s because functional programming does have some honest-to-goodness different perspectives. When one is combining object-oriented and functional approaches, it is inevitable that one will occasionally stumble by applying the wrong mental model to one’s code. Not long ago, I wrote some code that I expected to initialize a Dictionary once but which ended returning a new (empty!) Dictionary every time I referenced it.
Even the word “variable” highlights the different mindsets: a mainstream developer has no problem with a statement such as ”x = x + 1” because, well, x is a variable. In the functional world, “variable” is closer to the mathematical meaning of a holder that is not, at writing time, bound to a specific value (there I go with jargon, I know!). The functional mindset prefers to write code that assigns a specific value once and does not allow it to change. Scala has the simple and clear distinction between a `var` that can vary and a `val` that is immutable. (Of course, functional programs have state: they just carry it in the call stack rather than in stateful objects.)
There is also a significantly different approach to discussing common solutions to common problems. The object-oriented world talks about “design patterns” while the functional world talks about “laws” and categories. And while most design pattern discussions will start with a narrative description of a problem and how objects and their methods play various roles in solving a problem, many functional discussions will instead start with type signatures defining the form of the solution, and will often emphasize those definitions over narrative. Both are valuable approaches: narrative is more approachable, but definitions provide more specificity and may allow solutions to be combined or generalized.
While functional code is, I think, easier to read, write and reason about, object orientation is easier for discussions about program and system structure. Our platforms and libraries are built around objects, mutate state, and assume object terminology. And the truth is that OOP works. Most design and architectural artifacts of the past two decades use object terminology. It’s foolish to throw that away. Above all else, software development relies on communication and understanding.
Functional programming must stand or fall based on its utility on real codebases written and maintained by smart but busy and skeptical developers. Those developers are comfortable with the object-oriented mindset. Those who can move between functional and object-oriented paradigms can deliver more value to customers and that, not mathematical purity or tribal membership, is why you should be learning functional techniques.