Making Sense of Functional Programming

Functional programming is all the rage in the hipster dev community at the moment. Being wannabe hipsters ourselves, we try to make sense of what the fuzz is all about.

I have sensed a disturbance in the dev community. As if thousands of voices cried out in terror at the mere thought of functional programming and then suddenly stopped when they realized it’s kind of neat. If you’ve sensed the same, but you’re not quite sure what everyone is on about; read on!

What is this functional programming you speak of?

Functional programming has its roots in the exciting world of mathematics and lambda calculus. Conversations about it—you do have those, right?—quickly turn to stuff like first-class and higher-order functions, immutability, pattern matching, tail recursion, currying and so on. While these are all concepts and features you’ll find in functional languages—enabling, helping or even enforcing functional programming—the core principle of functional programming is avoiding side effects.

The core principle of functional programming is avoiding side effects.

It’s as simple as that. More or less. We achieve this lack of side effects by writing functions that are deterministic and referentially transparent. Those are some big words right there, but in practice they mean nothing more than that a function’s output depend only on its input. Such functions are called pure functions and they are the fundamental building blocks of functional programs.

A purely functional nirvana sounds nice and all, but if we want to do more than generate Fibonacci sequences we’re going to have to deal with side effects. User input for instance is not deterministic and persisting something to disk or database is very much a side effect. The way functional languages deal with these things differ, but the common principle is separating the pure from the impure. That way, we still get the advantages of functional code while interacting with the outside world in a sane way.

Rise of the functional language

For a long, long time functional programming meant taking a Haskell class at university and then conveniently forgetting all about it as quickly as possible. However, this is changing and there’s now an abundance of languages with functional features and even nearly pure functional languages around. Examples of such languages include Elixir, F#, Swift, Erlang and Rust and JavaScript—the most loved, and most hated, programming language in the world.

Some part of this recent increase in popularity is certainly down to available computing power. Functional languages are a wee bit more resource hungry than lower level imperative languages, and the puny computers of the 50s just weren’t powerful enough to handle them. Now that we live in the future, they are.

But there is another reason. Up until the 00s, a personal computer had one processor with one core. Now, even a mobile phone has at least two cores. Pretty soon there’ll be cores up to here and we should maybe try using them. Unfortunately, parallel computing is seriously hard to get right in imperative programming. Always has been. The lack of mutable shared state in functional programming makes it much easier. No need for locks, monitors or semaphores to avoid data race conditions, you get that for free. In languages like Elixir and Erlang, concurrent processes are used almost like objects in an object-oriented language. The difference is that the processes can run independently and on different cores or even machines with very little effort.

Process tree for an Elixir web server application
Absolutely fascinating shot of concurrent processes in a Phoenix Framework application written in Elixir running on the Erlang VM

What’s in it for me?

Even if you’re just not that into in concurrency or parallelism, there may still be some other aspect of functional programming that you do like and care about.

Functional programming encourages you to write small, single-purpose functions and to separate data from operations. This promotes reuse and helps you keep things DRY.

Testing functional code is easier than testing imperative code since a function’s output depends only on its input. This largely removes the need for mocks or complicated environment setup. If your functions are small and do just one thing, writing tests for them is a breeze.

Pure functions remove the need to keep a lot of state in your head when reading code and are thus easier to follow and understand. This makes it easier to debug, refactor and optimize code. In addition, a compiler can make optimizations that are just not possible for an imperative language.

Functional code is generally more concise than imperative. There’s less noise and more signal. You can write less code and focus more on solving problems. This leads to higher productivity and in the end more fun. Yay!

Last but certainly not least, functional programming is sufficiently different from imperative programming to make you flex your cognitive muscles. You’ll learn new ways to think about problems and get new tools to solve them. It’ll be fabulous.

Conclusion

Functional programming, while associated with lots of really long words, isn’t that complicated when you get down to it. Avoid side effects and you’re there. This leads to all kinds of advantages, one of which is easier concurrent and parallel programming. This is highly relevant today, and will likely become even more relevant in the future.

On the other hand, it’s not a silver bullet for all your coding needs. Then again, neither is object-oriented programming, and honestly we’ve kind of been treating it like it is for the last decade or so. It’s time we reconsider.

Alright, I’m going to stop now. Thanks for reading, I’ll just leave you this to ponder:

Functional programming is like describing your problem to a mathematician. Imperative programming is like giving instructions to an idiot. —arcus, #scheme on Freenode

You don’t really want to spend your life giving instructions to idiots, do you? Didn’t think so.