How to use powerful function composition in Javascript

Martin Novák
Jul 12, 2019 · 7 min read

Function composition is one of the most powerful differentiators between object-oriented and functional approaches to programming in JavaScript.

I will explain the difference between class hierarchy and composed function leading to practical examples of advantages of function composition and functional programming in JavaScript that I use in all of my own code.

Class hierarchy and RoboDog

In object-oriented programming, you define your classes.

For example, you specify a parent class Animal that has a method move. You continue by creating classes Cat and Dog which will inherit move from Animal and add their own methods bark and meow.

Then you decide to develop a class Robot which has a method chargeBattery.

Now, what if you want to create a class RoboDog that needs to move, chargeBattery and also, do a roboBark that enhances bark of your Dog? You need to inherit from both Dog and Robot but JavaScript does not allow you to do that.

To solve these and other issues, it is no longer recommended in object-oriented programming to use inheritance. Instead, you are expected to define an interface (which does not currently exist in JavaScript) for your class and instantiate classes that you would otherwise inherit to use them as dependencies.

Besides, your dependencies should be handled through dependency injection to improve your testability and flexibility, see JavaScript Pure Functions for OOP developers.

Your class RoboDog will look like this:

Function composition

Function composition is based on the use of monadic (unary) curried and preferably pure functions.

Function composition is a quite simple use of multiple functions where each function receives input and hands over its output to the next function:

In functional programming, you are defining expressions instead of statements. A function is just an expression as well, and as such, JavaScript supports higher-order functions which use a function as an argument or return a function as its output.

To make this even easier, you can define higher-order functions compose and composePipe:

compose and composePipe differ in the order under which they compose functions together:

Note that we could use a point-free style of code (tacit programming):

This is possible because compose(plusA, plusB) is a higher-order function. compose returns a function that is used to define your new expression.

If you like Unix, you can also relate function composition to Unix pipeline which works on the same principle: $ ls -l | grep key | less.

Itty-bitty math

If you look at the image above you can see three numbered sets of different colours that are connected by functions g and f. Function g takes argument Horse and returns Horn. Function f then takes argument Horn and returns Unicorn. Composition of those two functions is then a function takes a Horse and returns directly a Unicorn.

Because we are using pure functions that always return the same value for the same input, it is proven that we could replace our composed function by a simple function that just takes Horse and returns Unicorn. That is a principle that is used in Memoization.

Functional programming doesn’t make it just possible to better optimise for parallel processing. As you can see, it also provides the magic that allows us to skip processing altogether and just return the answers to the questions by skipping everything in between.

Function composition and RoboDog

The use of function composition is actually in a spirit similar to what we did in the object-oriented programming example with RoboDog and its dependencies. However, I believe that function composition is far more elegant.

You are not modelling your world using classes; you are only defining the functions that represent the desirable skills. Your final JavaScript module will be expressed like this:

Notice that the code above does not reference anything that it does not need which means that there is no mention of functions of Animal or Robot. Those are not unique to our RoboDog and we want to focus only on a new unique code.

To use all the features in your code you are freely using functions from Animal, Dog, Cat, Robot and RoboDog.

There is another significant difference between composition and objects. Objects hold internal data and status. They are stateful. Functions in functional programming, however, should be pure and stateless.

A pure function is driven only by its input to provide its output. It does not change (mutate) any other data, and it does not trigger any side effects. That makes it very simple, predictable, easy to test and easy to follow general programming best practices. These are things that a good programmer should care about.

In functional programming, you are intended to follow separation of concerns to decouple execution of a task from its implementation by the use of inversion of control principle and functional monads.

Even, if you don’t use monads (because of their definition: a monoid in the category of endofunctors, scares you), you can still decouple your code. Merely move the definition of functions into one place and execution, where you integrate and provide data, to another location. Ideally, do that on a level of completely different modules.

Cover your functions with unit tests and your integrations with integration tests and you will live happy-programmer life.

Break down your functions and use composition

You may be using functions as a box for a repeatable sequence of statements like this:

The above function trims the string argument, decorates it and then returns. In reality, it is not rare to see functions that are expressed by dozens of lines of code.

Single responsibility principle states that: Every function should have responsibility over a single part of the functionality. That is open to interpretation, but I can easily claim that the above function both trimming and decorating does two things instead of one.

Let’s try doing the same with function composition in JavaScript:

Composing your functions means that for every step of your program logic you have a function that is testable and reusable.

Test-driven development asks you to write a test first for any part of the functionality that you are going to implement, let it fail and then implement it to allow the test to pass. That is partially to ensure that your program won’t have any hidden untested logic.

By composing your functions you are always writing your code in a way that exposes the logic and allows for easy testing. Look at Making testable JavaScript code.

Create reusable code with partial application

The above example of simonSays function could be further improved by a partial application of the curried function.

Partial application means that you supply argument exposing the underlying function(s) of a higher-order function:

This allows you to create even more reusable code. Look at JavaScript ES6 curry functions with practical examples.

Investigate your code

Because we have been using pure functions it is quite easy to insert additional functions in the composition. See this example of logging:

If you are creating pure functions you will always be able to compose your code very easily without refactoring the previous code to support the new use case.

Conclusion

Function composition asks you to think differently about the way you write your code and rewards you with many benefits.

Hierarchy replaced by composition allows you to always focus on developing new unique code by thinking of skills instead of classes.

The point-free style allows you to shorten your code by taking advantage of curried and higher-order functions.

You are driven to build broken down atomic functions to create more reusable composable code for single responsibility principle and test-driven development.

Pure functions and partially applied functions allow you to advance your composition by creating powerful code that is very simple, predictable, comfortable to test and easily applies programming best practices.

Frontend Weekly

It's really hard to keep up with all the front-end development news out there. Let us help you. We hand-pick interesting articles related to front-end development. You can also subscribe to our weekly newsletter at http://frontendweekly.co

Martin Novák

Written by

Frontend Weekly

It's really hard to keep up with all the front-end development news out there. Let us help you. We hand-pick interesting articles related to front-end development. You can also subscribe to our weekly newsletter at http://frontendweekly.co

More From Medium

More from Frontend Weekly

More from Frontend Weekly

More from Frontend Weekly

Understanding `static` in React

4.3K

More from Frontend Weekly

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade