One trend that has started gaining some serious traction in the past couple of years is functional programming. Unlike an object-oriented approach, which encourages decomposition of a program into ‘objects’ which relate to a particular domain, a functional approach guides the developer to decompose a program into small functions, which are then combined to form an application. Once confined to the halls of academia, it has recently seen a resurgence as a popular tool to solve a number of the problems that we face in modern development, especially complex applications and distributed systems.
Trailing along behind the functional cheerleaders are a whole host of super-powered functional languages. These include such venerated languages as Haskell, Lisp and Erlang, as well as more modern interpretations including F# (a .NET language), Scala and Clojure (on the JVM), Rust (a server-side language) and Elm (a language based on Haskell for building web front-ends).
While it is wonderful to have such a varied ecosystem of functional languages, the reality is that for day-to-day work we are often restricted in our choice of languages and frameworks. I’ve been taking a look at some of the characteristics that define the functional paradigm and in this post I’m hoping to show you that you don’t have to use a ‘pure’ functional language to benefit from some insights that the functional approach gives us. By way of demonstration I’ll be building a small, functional front-end app in React and JavaScript*.
*I’ll actually be using JSX instead of Plain Old JavaScript, as it makes building React components really easy. Most of the concepts will work with standard ES5/ES6
Before we dive in to building our front-end, I want to touch on a couple of important functional concepts that we can use to make our app more robust.
Pure Functions
We all know about functions - they are the building blocks of any program. What makes functional programming so special? Pure functions are part of the answer. A pure function is a function where the return value is determined only by its input values, and which does not alter any external state. This has two important implications:
- For a given input the function will always return the same result, no matter how many times it is called. This means that our application is completely predictable - if we know what inputs it will receive, we can be confident of the outputs.
- Calling the function will not result in any observable side-effects. We can be certain that we will not experience any undesirable ‘emergent behaviour’ arising from the interactions between different functions.
Building an application from pure functions enables us to more easily reason about the behaviour of an application.
Immutability
An immutable object’s state cannot be changed once it is created. If we want to change the object, we can’t simply set a property on the object - we have to return a whole new object with that one property changed. This might seem arduous, but it comes with big advantages.
One of the advantages of immutability is in asynchronous programming: if a thread is operating on an immutable object, it can be sure that it is dealing with the latest version of the object. This allows multiple threads to operate simultaneously without worrying about what the other threads are up to.
While the advantages in parallel processing may not be entirely appreciated in JavaScript running in the browser, immutability can still give us big gains. The most apparent in a React application is that we can use simple equality checks to determine if a component needs to be updated: if two variables reference the same object, we can be sure that all data contained within the two objects is identical; if a property is different, the two variables will reference different objects. This is both efficient computationally and cognitively (===
is always more readable than a deep-equals!).
Another advantage to immutability is that it encourages us to keep our functions pure - if we can’t modify an object from inside a function, we can’t modify state external to the function. This means that we can be sure of making the most of the very tangible benefits of pure functions.
Currying and Point-Free Programming
A curried function is one which returns a function for every argument until the last argument is supplied. As an example consider the following code, which adds two numbers:
We can call add
with each argument provided simultaneously (invoking the function after each argument). Alternatively, we can store a partial application of the function - here, we are storing add3
. This partial application can later be applied to further arguments.
This is a good approach if we are going to re-use the function multiple times, or if we want to be more explicit about the meaning of a function. A good example is the following, which assigns “modulo 2” to “is odd”, resulting in more readable code:
This style of assigning partially applied functions is known as point-free programming. A good explanation of point-free programming can be found on the Haskell wiki. As the article notes, care should be taken when using point-free programming with higher-order functions (functions composed of functions) as it can easily result in code that is more obfuscated and less easy to reason about - precisely the opposite of what we want!
Functional Programming in JavaScript
Although JavaScript inherits its syntax from C-like languages, this is quite misleading. Douglas Crockford (author of JavaScript: The Good Parts) notes that “JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java”. JavaScript makes it easy to write in a functional style.
In this post, I’m going to be using Ramda. Ramda is a functional library that makes it even easier to use a functional approach with ordinary JavaScript. All Ramda functions are curried by default, making it straightforward to use a point-free approach where appropriate, with clean code and no weird-looking syntax. Ramda also provides functions which will help us to keep our data immutable. Ramda doesn’t guarantee immutability, as it operates on plain JavaScript objects. Alternatives exist that do guarantee immutability, for example ImmutableJS - Colin Eberhardt (prolific blogger and CTO of Scott Logic) recently wrote about using ImmutableJS with Angular2. For the purposes of this small project I like Ramda’s balance between a clean API and immutable data, and it doesn’t play nicely out-of the box with ImmutableJS (though it can certainly be made to).
Why React?
React is a great tool for building the view layer in an MVC-style web application. Rather than providing a full single page application framework like Angular, it focuses simply on rendering data, and it is very good at doing this. This is not an introduction to React, so I won’t go into too much depth here (the React Docs are an excellent place to start learning about React). Instead, I want to focus on what makes React an excellent choice for our functional front-end.
React applications are separated into components. These components should encapsulate a particular piece of functionality, and can be combined into more complex components and eventually into a whole application. The job of most components is to simply render data that it is given (for example, to display a single comment in a forum), or manage some small interaction (the click of a button, entry of text into a form). This sounds a lot like functional programming!
In fact, React makes it really easy to build components out of functions. Here’s the canonical “Hello, world!” example as a React component:
Here our component - HelloWorld
- is defined as a pure function. React can then render it just as it would any other component - we do this by calling ReactDOM.render
with our component and a DOM element (which we have given the id 'app'
).
That html-looking syntax there is actually JSX. <div></div>
returns a React element that indicates that an html div
element should be rendered here. We might also want to render another React component - we can reference our HelloWorld component using <HelloWorld />
. JSX makes it easy to compose React views inside JavaScript - for a more in-depth explanation, check out the docs.
What if we wanted to re-use a component for displaying different data? In the following example, our component greets someone by name:
We’ve defined a component that can say hello to anyone by name. Our component accepts some properties (props
) that have been set by its parent component - you can see this inside the ReactDOM.render
method - we are passing the prop name="Bob"
to the GreetSomeone
component.
In general, this is how components are built in React - a parent component will define some props that are passed down to its children. When ReactDOM.render
is called React builds a virtual representation of the DOM and renders to the real DOM. It looks like every time we call ReactDOM.render
the entire real DOM is re-rendered, but this is not the case: behind the scenes React builds a new virtual representation of the DOM and does some very clever comparisons to work out what changes to make to the real DOM. Again, the docs have an excellent explanation of how this comparison - normally O(n3) - can be turned into an O(n) problem with a couple of assumptions. This makes React’s approach of re-rendering the whole virtual DOM practical.
This is all great stuff, as it allows us to build really simple components that are easy to reason about.
So we’ve built a component using just functions - let’s see what happens if we stick a few together!
Functions as Components
I’ll be building a simple forum app which displays comments. As far as possible I’ll try to keep it functional - that is, use pure functions with immutable data. We’ll start by breaking down our app into pure functional components that will display our comments, and then we’ll plug in some data.
Let’s start with the top-level component - App
. Just as before, we can define our component as a pure function. Our inputs will be the title and subject of our forum discussion, and our list of comments. On top of that, we’ll also display our title, subject and list of posts using Title
, Subject
and PostList
components like good React programmers.
Pretty straightforward, right? It’s really easy to see what’s going on here. Our App
component is rendering Title
, Subject
and Post
components inside a div
element. It’s passing down the title
to the Title
component, the subject
to the Subject
component and the posts
to the PostList
component.
So far, so easy. Let’s take a look at PostList
- it’s calling postComponents
to generate the Post
components from the array of posts. What does this postComponents
look like? We can use currying here:
This uses Ramda’s map
function to partially define a function that maps the given expression (a conversion from post to Post
component) over an array of posts.
For those unfamiliar with the functional style, this can be quite difficult to follow so I’ll break down what it’s doing. We want our postComponents
function to convert an array of posts into an array of components. A first pass at a function that does this might start with an empty list and add components to it one at a time:
This is fine, but it is quite verbose and not very readable. We need to follow the flow of the function through variable initialisation and loop to determine that it will result in an array of Post
components.
As a second pass, we might realise that JavaScript’s Array.prototype.map
is up to the job:
This is better, however it is still verbose. We need to define a whole function in order to define our customisation of the map
function. This is where currying can help us - it allows us to store references to partially defined functions that we can use later.
We could just use the posts.map
function directly inside our PostList
component, however storing a reference to the function promotes code re-use and allows us to keep our code very readable.
Now that we have our list of Post
components, let’s take a look at the Post
component itself. We need to display an author and a comment - so let’s break those up into components too.
Take a look at that - they’re all pure functions! The Post
component has an author
and a comment
in its props
, which it passes down to the Author
and Comment
components respectively.
Our Author
component is doing something similar to the PostList
component - it’s calling the authorComponents
function. This function should return an array of components to display all properties that are present on the author
object. This is defined as follows:
Here, we’re using a few JavaScript language features to make our code concise and readable.
The ES6 arrow function syntax replaces the function
declaration. This makes it semantically clearer that “author
maps to the following array” or “author
maps to the following element”.
Our use of the ternary operator (?:) makes it easy to shorten if-else
blocks in order to make our code more readable.
Finally we recognise that when a property is present on an object, the first argument to the ternary expression will evaluate to true; if it is missing, it will evaluate to false. This makes it easy to conditionally include or exclude React elements based on properties in our object.
Let’s recap - we now can now display a forum and thread of posts, with each post displaying some information about the author and the comment. And we’ve done all of this using nothing but functions. Not only that, but we haven’t modified any state outside of our functions. This has profound implications for testing - it means that we can write tests for our functions and be sure that no external interference will change their behaviour - that’s pretty impressive.
Generating the Sample Data
For this example I’m going to simulate a few comments from a few authors.
Here, we have a couple of interesting functions to generate sample data. nthWrapped
uses Ramda’s pipe
function to build a function that takes the modulo of the input with the length of the array (using the handy flip
function to swap the order of the first two arguments of mathMod
) and then returns the element at the resulting index. nthPost
takes an index and merges the result of calling nthWrapped
on both the authors
and comments
arrays into a single result. We can use this as an argument to Ramda’s map
function to generate another function that returns posts in a given range.
We have effectively provided a “stub” version of the postsInRange
function - we could easily swap this out for a real version. This is one of the great advantages of functional programming - because each of the functions are small and simple, and because they do not modify anything external to the function itself, they are easy to replace.
Rendering the App
Once we have our data, we can simply call ReactDOM.render
, as we saw in the examples. We can use Ramda’s range
function. I’ll then render them into the html element with id="app"
. Here’s what that looks like:
Bonus - RxJS Stream
Great - we’ve got an app that renders comments! But we can do better than that - we might be looking at a really popular post, and we want to view comments as they come in. Wouldn’t it be nice if we could render a stream of incoming comments? Thanks to the functional style in which we have written our app, we can!
RxJS is a library that makes it easy to handle streams of data in JavaScript. It is written in a functional style and treats streams of data in a way analogous to arrays of data. This makes it very easy to plug in to our existing implementation.
Instead of rendering posts in a given range as in the previous example, we want to call render
every time a new post is available from our stream. We can let React do the heavy lifting to ensure that a minimal set of updates is applied to the DOM.
Here’s the code:
We set up a source for our posts. This is simulating a post coming in every two seconds, using the same nthPost
function that we defined in our previous example. This could be swapped out for real data in a production app.
We then set up a subscription to our event source. This is doing a couple of interesting things. scan
is a method on the Rx.Observable
postSource
. It acts very much like the reduce
function - we provide an initial value and an accumulator, and it returns the result of calling the accumulator over all of the elements in the stream. The difference between reduce
and scan
in RxJS is that scan
will return intermediate values - it will return every time the stream emits an item - whereas reduce
will wait until the stream has completed. Our accumulator here is simply appending the next value to our current accumulated value.
The result after scan
is called is an observable that emits an array containing all the posts emitted so far, every time a new post is added.
map
is then called to return a React element that wraps our posts - here defined as the app
function. This also returns an observable, which we can subscribe to in order to render our posts.
This amazingly small amount of code achieves something quite complex - we now have a dynamic application!
Is Functional Programming The Way Forward?
I think that we can learn a lot from the functional paradigm and that it can result in cleaner, more readable and more robust code that is also easier to maintain. Though this post is only meant as an introduction, hopefully it will inspire you to look into functional programming and perhaps use some of the approaches outlined here.
Where to go next? If you’re using React, then redux provides a functional approach to managing state for your apps. It has a large and growing ecosystem of tools and middleware and comes with features such as time-travel and undo-redo practically for free - thanks to its use of immutable states. Colin’s written a post on that too!.
There are frameworks out there that take a much stricter approach to building front-ends in a functional style - elm takes its cues from Haskell and provides a pure functional experience for programming in the browser, while Reagent and re-frame allow you to build front-ends with ClojureScript.
For now, I am very happy that it is so easy to strike a balance between practicality and functional style in JavaScript. Pure function components in React make it really easy to put together simple, easily understandable applications. The approaches here do not answer every problem - stateful components and lifecycle hooks, for example, will still require fully fledged components at some level (for e.g. optimising efficiency, manipulating DOM elements). I’d like to explore this more in the future, and see what other examples we can take from functional programming.
You can check out a version of this app on jsbin.