Functional Programming is on the rise
Looking at trends in programming for the past 60 years I cannot help but notice that functional programming is on the rise, it is becoming more widespread. But what do I mean by that?
Now, look at any language popularity chart circa 2019. You cannot find any of the “functional programming languages” anywhere outside of small niches. Dominant languages are Java, JS, C++, Python, etc — languages one would hardly call “functional”. Around 15 years ago I attended a lecture by Bjarne Stroustrup, creator of C++, and, when asked about functional programming that “everybody is talking about”, he said: “that’s the thing — everybody talks about functional programming, but nobody uses it”. However, nowadays the trend is real. Read on.
Style
To start, how do you even define what “functional programming” is, when different people put very different meaning into the term itself? To answer this question let’s contrast it with imperative programming¹:
In computer science, imperative programming is a programming paradigm that uses statements that change a program’s state.
The emphasis on the state here is mine. In imperative programming style, when faced with a problem of finding a sum of values in a list, we’d write something like this:
var sum = 0 // initial program state
for (x in list) { // loop over elements of list
sum += x // change program state
}
However, we tend to write this kind of code less and less even in traditional programming languages. Instead, more and more, we find ourselves writing something like:
val sum = list.sum() // call sum function
An actual implementation of sum()
function would still be typically imperative, but this imperativeness is not as pervasive in our application code as it used to be 20 years ago.
What’s more, all mainstream programming languages nowadays support some form of lambdas or anonymous functions. It was not the case just 20 years ago — neither Java nor C++ had this language feature back then. The main use-case for lambdas is to enable APIs based on higher-order functions — functions that take other functions as parameters. With lambdas you can write even more code in functional style, without explicit manipulation of state, like:
val goodSum = list.filter { it.isGood() }.sum()
Syntax
A function is a mathematical concept and in math we compose a function filter
with a function sum
like this: sum(filter(list, predicate))
, so the function names would be written in reverse order of their actual application.
It used to be same way as in maths when programming with functions, too. For example, in Python (circa 1990), as it was quite customary in languages of that era, you call a function to find a length of a string as len(str)
, but in more modern languages this typically looks like str.length
or something similar.
This dot notation for object.method()
was introduced in Simula (circa 1962) as a part of its object-oriented innovation and became widespread when object-oriented languages went mainstream in 1990s. Most developers who live today were raised on this x.one().two().three()
syntactic tradition in which the code is fluent —it reads and works left-to-right. While we can still understand that three(two(one(x)))
means essentially the same, it takes more time for a mind of a modern developer to parse.
Truly mathematical functions like sin(x)
still use a traditional maths notation in modern programming languages, but the dot notation of x.f()
is becoming a standard for calling all other kinds of functions as more languages provide some form of extension functions² that decouple notation from the actual object-oriented programming with its methods. What a twist of a history!
Types
Using and writing higher-order functions like filter
becomes a norm, and so does support for functional types in statically typed programming languages. Structural functional types are becoming de-facto standard, as you can find them in every prominent language that was introduced in the last ten years, like Go (2009), Rust (2010), Kotlin (2011), TypeScript (2012), and Swift (2014).
Even Java³, the old guard, is forced to compromise with the dawn of this functional world. Functional types in Java are technically nominal (you must give them names like Predicate<T>
as opposed to structural (T) -> Boolean
), but Java still has a concept of a structural function type that allows passing any structurally-compliant method reference as an actual argument to a higher-order function.
Evolution
Programing languages, type systems, notation and tooling all closely coevolve. The appeal of x.f()
notation is not only in its readability. Your IDE knows the static type of x
and can suggest you appropriate functions to apply to x
when you press .
on the keyboard. More complex and functional types contribute to the trend of writing types on right, too⁴.
Where does this evolution lead us in the future? I do not predict the future, but I look at the past and I work to build the future. It seems that we are going to have more functional concepts in our programming languages. As functional style of programming, a style that shuns changes in program state, becomes more widely adopted, people start to notice the difference between mutable and non-mutable things in their code. Developers are starting to avoid excessive mutation, considering it a code smell⁵.
It is a sign of the functional era that IntelliJ IDEA (an IDE for a Java language, a language from imperative object-oriented era, that lacks concise syntactic distinction between immutable values and mutable variables⁶) underlines mutated variables to emphasise and bring attention to them.
Further reading and footnotes
- ^ Imperative Programming, Wikipedia
- ^ Extension-oriented design
- ^ I still consider Java to be the greatest language of the 21st Century, see
A Tribute to Java - ^ Types are moving to the right
- ^ Code Smells: Mutation, IDEA blog, by Trisha Gee.
- ^
final var
in not concise, nor something you’ll typically find used.