This post assumes some knowledge of OO and procedural programming paradigms
Quick overview of Object Oriented and Functional Programming
Firstly here’s a brief overview of the defining features of functional and object oriented development:
- Structuring procedural code into classes and objects
- Classes and objects are encapsulated
- State/variables are shared within a class which can cause side effects
- Easier to reason about a problem as Objects are split into related “things”
- Imperative view on programming where code is written in terms of goals and what is required
- Pure functions are encouraged so if the same input is given, the same output will always be returned
- Functions can be used as variables and passed as parameters to other functions
- Combination (or composition) of functions
- Sate is not shared, and all data must be immutable, leading to no side effects so data/state outside a function is not affected
- This leads to functions being able to run independantly of each other and in any order
- Declarative view on programming where code is written in terms of instructions and exactly how data/actions are processed
There are a lot of posts about functional programming and how it’s great because of the reasons mentioned above plus various other reasons I’ve not included, but I won’t regurgetate that content in great detail. After all it’s covered in great detail in many popular places which are all saying the same thing:
Instead, I’ll cover the real basics, and my thoughts which may help people who want to get an understanding of the bigger picture.
Functional vs Object Oriented Programming - real life comparisons
Instead of going into too much detail, here’s 2 code samples - one in OO and one written with FP in mind, showing how the same goal/output can be approached with each programming technique.
This is an extremely simple example to illustrate what I think is one of the most important asect of functional programming which is the usage of pure functions. In the object oriented example, the
transformToUppercase() function is impure as it relies on the
type variable which is shared within the
Food class. In turn, this means there’s now mutable data flying around so there’s a chance that all sorts of things can go wrong if variables are re-assigned, for example.
The functional example, however, doesn’t have the shared
type variable, and instead operates as a pure function which takes the argument
type and returns a new function. This means the
transformToUppercase() function doesn’t create side-effects and makes it easier to test and understand what’s going on.
Of course, thats’s not all there is to functional programming. There are a few other defining features and techniques which can be used to make an application in a functional kind of way, and they are used at different levels in different situations, which I think causes confusion when it comes to defining what functional programming actually is.
The key’s to unlock the doors of functional programming
I’ve already mentioned that I consider the most important part of FP is pure functions. Aside from this, there are a few other patterns which are crucial.
Keeping data immutable means ensuring it can not be changed after it’s defined. If data can be changed, it is possible for other functions or parts of code can suffer as a consiquence if they relied on a certain structure or data set. There are libraries like Immutable JS and differing techniques to help keep defined data constant and “frozen”.
Another crucial part of FP is being able to clearly declare what you want your program to do in terms of functions. Creating small, re-usable functions is key, and composing these functions together to form larger functions is what makes functional programming so flexible. This is done by functions returning other functions, and/or accepting functions as parameters.
Composition can be facilitated with the use of currying, which is where a function is broke down in to a series of functions which are returned from each other based on the arguments suppled to the first function. You may have seen/used function composition whilst using
compose() function from the Redux library.
More about these kep parts of FP are explained in great examples below…
Further excellent examples
I’m a huge fan of learning by example, and I found a resource on Github which does just that for functional programming. I found it hard to find anything like this, and at the beginning I could really have done with this to make the concepts slot into place quicker.
Here’s the link which gives examples of the same program written in many different ways, starting off at OO programming and leading up to hardcore functional programming gradually. It perfectly illustrates some of my key points below.
Chaining vs function composition
It can be confusing when first trying to learn the basics of Functional Programming because almost all examples are using the same ES6
filter() functions. What’s more, these functions are used in chains with libraries like Lodash using the
_.chain() function, so how do these compare?
Here’s an example of the Lodash chain using a
The ES6 and Lodash versions of
filter() are different. They can be chained without the use of Lodash chain, but cannot be composed together using the
compose() type functions such as:
It’s worth noting that I find the vast majority of data manipulation can now be done with the ES6 array prototype methods.
.map() for example.
In my opionion, there not enough mention of some key points which I feel are causing the “steep learning curve” for newcomers and keeping people from adopting fucntional programmng in their day-to-day development. Here are these key points:
The declarative nature of FP
Functional programming is widely seen as declarative as application state passes through functions which describe what is happening to the data, not how it’s happening. This often leads to 10 or 20 lines of procedural or imperative code can be expressed in something like 5 or 6 lines using some common utility functions.
A lot of resources covering functional programming cover these utility functions
concatAll(), and you may be left with the question “Yeah but what else do I need to know when manipulating data?”. And the answer is not too far from “Nothing!”. These 5 functions cover the vast majority of manipulation needed on collections of data, which, at a very high level, is most of what programming is!
The point I’m making here is that functional programming at a basic level can be seen as no more than the abstraction of data flow into functions which describe how the data is to be processed, making the code readable, promoting the use of pure functions etc.
It depends how far you go…
FP isn’t an all-or-nothing type of thing.
There are many different parts of FP which can leveraged at all levels, such as:
- Using pure functions
- Passing functions as parameters
- Using data collection utility functions such as map, filter etc
And I think they all play a part in different scenarios. This is really a “jump right in and start devving some FP” type of scenario, and once you do that you’ll see which bits you’re more comfortable doing in a OO or FP way.
OO and FP are not mutually exclusive
I think the reason object oriented programming is so widely used is because it makes code easy to undertand what’s going on and groups “things” logically into classes. This does have huge advantages such as ease of readability namespacing functions, but this isn’t as much of a requirement for functional programming.
You’re probably using functional programming already
then() functions to clearly and purely display the code as opposed to creating callback hell.
It all comes down to the situation you’re in, and what you feel most comfortable doing. Having said that, I think to fully understand the landscape and breadth of the language, it does make sense to understand both OO and FP to a certain point, and allow the transfer of skills to be used effectively. From my time doing functional programming it’s introduced me to many concepts I’s never used before.