After Decades of Neglect, Functional Programming is Finally Going Mainstream. Why Now?
Functional programming is hardly new. I remember coding a lot of LISP when I was at university in the early 90's. That was 25 years...
Table of Contents
Functional programming is hardly new. I remember coding a lot of LISP when I was at university in the early 90's. That was 25 years ago, and the language was already quite a bit older than my college-age self.
The advantages of FP have long been recognized. Successful software development is largely about keeping complexity under control as applications scale under real-world conditions, battling unrealistic deadlines as we lard on more and more features. This is so much easier when your application is made up of highly testable pure functions and lacks icky side effects and mutable global state.
And yet no functional language has achieved anything approaching mass adoption. By this I mean the kind of intergalactic hegemony first enjoyed by C in the 70's, before it passed the mantle to C++, Java and then JavaScript over the ensuing decades. None of the second-tier contenders (Python, PHP, Perl, Ruby, C#…) are functional either.
But now something magical is happening. I'm talking about Clojure, of course.
Just kidding! It isn't that a new functional language has taken the world by storm, it's that the functional potential of the reigning champ is suddenly coming to the fore. I'm helping out right now with this React/Redux-based mobile app we're developing, and I find myself writing code like:
aliasesList.reduce((allMatching, matching, index) => {
if (matching.count() > 0) {
const expanded = allAliases.take(index)
.concat(List.of(matching))
.concat(allAliases.skip(index + 1))
.filter(aliases => aliases.count())
.reduce((current, aliases) =>
current ? current.flatMap(
i1 => aliases.map(i2 => i1.concat(i2))
) :
aliases.map(alias => List.of(alias)),
null);
return allMatching.concat(expanded);
} else {
return allMatching;
}
}, new List());
Hey, you got your LISP in my JavaScript!
So why has FP been neglected for so long by the programming masses? And why, at last, is it starting to gain mainstream adoption?
Down with Nouns
The answer to the first question owes much to an overarching trend in software development. After graduating from university I was swept away by the object-oriented tsunami and didn't write another line of LISP for over 20 years. The software development community had decided that OOP was the One True Way—a trend amplified by the invention of Java a few years later—and didn't have enough collective attention to devote to FP as well.
Under the triumvirate of encapsulation, inheritance and polymorphism, OOP promised a cure for the scourge of software complexity. In recent years, however, its weaknesses have become increasingly apparent. Rigid object hierarchies with fragile base classes make for painful schema evolution. Spreading state all over the place leads to concurrency issues and unpredictable side effects. As the nouns of OOP have fallen from favor, appreciation of FP's verbs has risen accordingly.
I poked a bit of good-natured fun earlier at Clojure, but due credit should be given at this point for its contribution to the FP renaissance of recent years. By addressing many of the practical issues that plagued the LISPs of yesteryear, Clojure introduced a whole new generation of developers to FP. It also spurred the creation of Om, which has had a massive impact on the evolution of today's JS ecosystem (more on that later).
Big Boy Pants for JavaScript
Besides disillusionment with OOP, the two questions mentioned above are bound together in two further trends: the emergence of JavaScript as a full-fledged general-purpose programming language and the embrace of FP by the broader JavaScript ecosystem.
At the turn of the decade, most web development was still server-driven, with client-side script playing a supporting role. A few pioneering Ajax-driven apps like Gmail, however, had already demonstrated the appeal of single-page apps that run entirely in browser, treating the server mainly as a centralized data store. Low latency web apps that look like desktop apps were clearly superior to the CGI-driven clunkers of the early web.
Reinforcing this trend was the release of Google Chrome in 2008 and particularly the step change afforded by its V8 JavaScript engine. Blazing fast JavaScript was a precondition for the creation of soup-to-nut frameworks for "single-page apps", led again by Google with AngularJS. V8 is also at the heart of Node.js, a standalone JS runtime used mainly for server-side development.
Suddenly JS wasn't just for script kiddies anymore. Angular and its brethren, along with Node, have led to an explosion in JS usage over the past few years.
Function and Form
What does all this have to do with functional programming? By his own account, Brendan Eich (who invented JS) was hired into Netscape in 1995 to create Scheme for the browser. Though he succumbed in the end to management's insistence that the language "look like Java", it retains some crucial aspects of FP languages (e.g. first-class functions) and has been described (a tad hyperbolically) as "LISP with C syntax".
The web offers millions of lines of evidence that JS can be used to write imperative code, object-oriented code and just plain god-awful spaghetti code. But far more than other C-like languages, it has the basic plumbing to serve as the foundation of a true functional language.
Functional stalwarts map
and reduce
were added to JS (technically ECMAScript) in 2011. ECMAScript 2015 (née ECMAScript 6), added a number of other functional-friendly constructs include const
and the beloved fat arrow, with its concise syntax and non-insane this
binding. Most ES2015 features have yet to gain widespread browser support, but the Babel transpiler has made this largely irrelevant since you can use ES2015 (and even ES2016) constructs and compile them down to universally digestible ES5.
Equal React-ion
AngularJS was an important factor in the JavaScript boom, but with roots in Java and OOP, it is anything but functional. Over the past couple of years, Facebook's React has imposed itself at impressive speed as the client-side JS framework of choice. It is complemented by the Flux architecture and Immutable.js library, both created by Facebook as well. (It's intriguing how much the rise of functional JS coincides with Facebook elbowing Google aside to become the JS framework supremo.)
React feels like a very functional approach to mapping application state onto web views. In fact, the latest version introduced a simplified syntax for side effect-free pure components.
React addresses only the problem of displaying data, however, which is why Facebook recommends Flux for the broader application architecture. As Flux is just a set of basic principles (stores, actions, centralized dispatcher, unidirectional data flow), many competing implementations have been vying for dominance. None had emerged as a clear winner until the recent appearance of Redux.
Redux is based on three principles: a single centralized data store, state mutation triggered only by emitting actions and pure functions (a.k.a. reducers) to modify state.
When used in conjunction with Immutable.js, Redux starts to look a heck of a lot like Clojure's Om. It has always been possible, theoretically, to do FP in JavaScript, but React, Redux and Immutable.js finally offer JS developers a practical basis—developing pure side effect-free reducers manipulating immutable state in taut ES6 syntax—for creating large-scale functional applications. The popularity of this approach (and thus of mainstream FP) is exploding: when I first noticed Redux a few months ago, it had about 500 stars on GitHub. It now has over 11,000.
Functional Future?
It's a bit early to say whether the new-found penchant for functional JavaScript is here to stay. The JS landscape has been so unstable in recent years that the rapid-fire emergence of ever newer Frameworks to End All Frameworks has become a bit of a joke. But functional programming's long pedigree and underlying appeal suggest that it is unlikely to disappear. Even if the concrete implementations are supplanted, it looks increasingly probable that the future of modern software development—at last!—will be functional.