Skip to main content

Ascetic masochism of Functional Programmers?

Paradigm for monks?

Functional Programming (FP) is becoming a trendy buzz word. It has suddenly became very popular in the industry. For people not familiar with the paradigm, it seems as if it pop out of nowhere as a fresh, innovatory approach to software development. But FP is not a fresh concept. In fact I remember exactly when I first read “Why Functional Programming Matters” [1] paper – somewhere on page 3 it is stated “(…) with recent languages such as Modula-II and Ada”. I remember that I stopped reading, paused for a second with a thought “Ada? Recent language?” I went back to the first page of that paper to learn with horror that it was first published in 1986! I was 2 year old at that time! But Functional Programming did not emerged in the 80s, it is far more older concept – almost as old as the computing industry itself (some argue that even older). Covering the history of Functional Programming could be a topic of a separate post. Suffice to say – it is well established paradigm, which has proven itself to be a robust solution for variety of problems.

But what can we really say about Functional Programming, beside the fact that is becoming popular? What does it mean to write FP code or what qualifies a language to be called a functional programming language? Does the fact that your language now supports a lambda expression or the fact that you are using immutable data structures makes you a Functional Programmer?

“Of course these days lambdas became very trendy. You have lambdas in C++, you have lambdas in Python and you have lambdas in Java. So here is Duke – the icon for Java – looking very smug. Congratulations Duke, you’ve finally caught up with were Alonzo Church was in 1936” — Philip Wadler [2]

So what does it mean to be Functional Programmer? If you google the question you will learn things like:

  • In FP there are no assignments and no variables
  • Once given a value it will never change
  • no side-effects

So it is pretty much no, no, never and no.

“The functional programmer sounds rather like a medieval monk, denying himself the pleasures of life in the hope that it will make him virtuous.” — John Hughes

But that seems a bit odd, doesn’t it? There must be something more to it, right? The concept of “purity” can not be just there for the ascetic masochism of those who practice the paradigm.

The answer is: yes – there is much more to that.

Why Functional Programming matters?

As engineers we endeavour to achieve simplicity, because software development is hard and complex. That is why all divide-n-conquer solutions seem so appealing. We strive for modularity. Ability to reason about something less complex, something that we can comprehend.

To give you and example: why suddenly “microservices” became such a popular concept few years ago? Different people will give you different answers, but it all boils down to one fact: promise of simplicity. A hope, that you can divide your complex problem into subproblems, which are easy and solvable, and combine subsolutions to craft the final answer. What people forget is the fact that when you divide a hard problem into smaller problems, the complexity does not magically disappear. It’s still there, waiting patiently, ready to strike when you least expect it. In case of microservices for instance, you move your complexity to your topology & network – which, as we know it, has its own set of problems [3].

If you really think about it, most of the time when complexity comes back at you in, it is when you try to merge you “subsolutions” together. Then it turns out that you never removed the complexity – you’ve just postponed it.

Functional Programming also embraces a divide-n-conquer approach. Thus the question you might have immediately is “What makes FP so special?”. The difference is that Functional Programming gives you a modularity in a true sense. Modules that you work with are context independent. Once created, tested and deployed, the module will behave as expected, regardless of its surrounding. “Does it mean that complexity disappears?” you might ask. The answer is: no, of course not! Obviously complexity is still there. The difference is a fact that FP has more then few decades of research of how to deal with different issues & problems that might occur. It’s still a working field and there is of course a chance that you will run into a problem, that has never been delt with – a problem that will require a unique, innovative approach. But to be fair, chances of it are small.

You might wonder how is that unique in our industry. Well, let’s take a look at those “microservices” one more time. They are not really a new concept. Just a little more then a decade ago our industry was all excited with SOA, few years before that we had CORBA. Same ideas, different names. Same set of problems that were never solved!
Something that is wonderful about FP community is the fact that it actually reads research papers. This makes it exceptional in our industry, as you will not see a concept that e.g emerged in the 80s to reappear 15 years later under different name. That is truly unique and invaluable – we can only progress if we “know” what we already know.

Modularity

Functional Programming orbits around the concept of a “pure function”. This purity is simply treating functions like mathematical functions, where if for a given argument from the domain exists a value from the codomain, then that value (and no other) will always be returned for that argument. This concept is a powerful one, because you completely loose notion of time – source of so many programming errors. There is no global context, no race conditions. But that is just a tip of the ice berg. If a function f for input of type A returns a value of type B and a function g for input of type B returns value of type C, then we can construct a function h (that goes from A to C) by simply passing values between function calls. With simple axioms we can reason about something more complex.

This is a modularity in pure sense. Ability to divide problems into subproblems, solving them to finally compose them into final solution. This is all we really strive for as programmers. You can reason about functions f & g separately, you can test them separately to check how they behave for given conditions. Since those functions are pure, they are context independent and so composing f & g gives you a function that is guaranteed to work.

There is one more even powerful feature in functional programming then function composition called – “propositions as types”. It such powerful & useful concept that it truly requires a post of its own. For now to keep the reader intrigue, it is suffice to say that proposition as types shows a correspondence (FP folks would say isomorphism) between logical theorems and types as well as correspondence between proofs and implementations. To put it in other words, in strong functional programming languages if your code compiles (both type signature & implementation) – you have immediate proof it works. How cool is that?

So where is the catch?

Functional Programming seems appealing. But as mentioned before, complexity never disappears. It might be moved, postponed, shifted – but it is still there. Take few functions as an example:

 // pure functions?
def random: Int = ???
def currentDate: Date = ???
def findById(id: Long): User = ???
def calculateTax(value: BigDec) = 
   if(someConditions) 
         throw new Runtimeexception("error") 
   else ???

None of those functions are pure. Functions random, currentDate & findById return different values for given argument. Function calculateTax seem pure, but for given number of conditions it’s side-effecting. None of those functions can be treated as mathematical functions. They rely on some global context and thus can repeat different values for same input. Does it mean that in Functional Programming you can not get access to current date or fetch user from data base? Functional Programming would be considered pretty useless if that was the case. As repeated few times, complexity never disappears and the question remains to where it is shifted. Functional Programming brings a robust & sophisticated box full of tools that were designed to handle different types of complexity. Tools that were both researched and widely used in the field for decades, proven to be very effective. Exploring that mystique toolbox is however a topic for a separate set of posts.

Disclaimer

There actually different approaches to do Functional Programming. Lazy vs eager evaluation, weak vs strong FP, static typing vs dynamic. Author of this blog is biased towards strong, lazy, statically typed FP.

References

[1]“Why Functional Programming Matters” by John Hughes
[2]“Propositions as Types” by Philip wadler
[3]The Eight Fallacies of Distributed Programming