Point-Free Style in JavaScript

  • 0

  • 0

  • 0

Point-Free Style in JavaScript

Point-Free Style in JavaScript

The Issue

Have you ever seen code like this before?

fetch('https://api.example.com/endpoint')
  .then(toJSON)
  .then(handleResult)
  .catch(handleError);

My first encounter with this style left me quite puzzled. toJSON, handleResult, handleError – what are they here? Are they functions, and if so, where are their parameters? How can they run without ending with () to make a function call? Or at least, where are their input parameters?

Many questions swirled in my mind, but at that time, there was no one to explain it to me. What you encounter frequently becomes familiar, so I started emulating this style, implicitly thinking, "Oh, I'll just write it like this, and it will work."

It wasn't until later that I understood that this style is called Point-Free. So, if it was initially unclear, why do people still use it? Is there something mysterious or interesting about this way of writing code? Let's find out in the following article!

Point-Free Style

Point-Free style means not specifying arguments for each function application. The term "Point" refers to a function's parameter, and Point-Free means there's no "place" for those parameters. This model aims to make readers focus on what a function does, not caring about the specific names of its parameters.

Returning to a simplest example, we create four functions that, just by looking at them, you can tell what they do:

const testOdd = x => x % 2 === 1;
const testUnderFifty = x => x < 50;
const duplicate = x => x + x;
const addThree = x => x + 3;

Then, we apply a series of transformations to a list of numeric data:

const myArray = [22, 9, 60, 24, 11, 63];

const result = myArray
  .filter(testOdd)
  .map(duplicate)
  .filter(testUnderFifty)
  .map(addThree);

Looking at the data flow, from top to bottom, we filter out odd numbers, double them, filter again for numbers less than 50, and finally, add 3 to all of them.

With this style, all you see are function names, even in the data flow. This style achieves conciseness, but you have to choose meaningful, understandable function names.

Returning to the opening example, if written in the conventional way, your code might look like:

fetch("https://api.example.com/endpoint")
  .then((res) => res.json())
  .then((resJSON) => {
    const { data } = resJSON;
    const dataFiltered = data.filter((item) => item.active === true);
    return dataFiltered;
  })
  .catch((err) => {
    if (err instanceof RangeError) {
      throw new RangeError("The number is outside the range");
    } else if (err instanceof EvalError) {
      throw an EvalError("The code could not be evaluated");
    }
  });

A bit too much to read and understand, right? Let's "refactor" it a bit:

const toJSON = res => res.json();
const handleResult = data => data.filter(item => item.active === true);
const handleError = err => {
  if (err instanceof RangeError) {
    throw new RangeError("The number is outside the range");
  } else if (err instanceof EvalError) {
    throw an EvalError("The code could not be evaluated");
  }
};

fetch("https://api.example.com/endpoint")
  .then((res) => toJSON(res))
  .then((resJSON) => handleResult(resJSON))
  .catch((err) => handleError(err));

Better, but there's still redundant code. Let's make it Point-Free:

fetch('https://api.example.com/endpoint')
  .then(toJSON)
  .then(handleResult)
  .catch(handleError);

Pros and Cons

The most apparent advantage of Point-Free is that it focuses on functions rather than data, making code shorter and easier to read if you choose good function names. When combined with libraries following the Point-Free style, like ramda.js or lodash/fp, which provide numerous utility functions, it can create consistency in your project.

The second example, after being fully converted to ramda.js, might look like:

const R = require('ramda');

const isOdd = R.pipe(R.modulo(R.__, 2), R.equals(1));
const isUnderFifty = R.lt(R.__, 50);
const double = R.multiply(2);
const addThree = R.add(3);

const handle = R.pipe(
  R.filter(isOdd),
  R.map(double),
  R.filter(isUnderFifty),
  R.map(addThree)
);

const myArray = [22, 9, 60, 24, 11, 63];
handle(myArray);

However, what's an advantage for some might become a disadvantage for newcomers or those unfamiliar with the Point-Free style. It can be harder to understand or take more time to approach.

Conclusion

Point-Free is a programming style that focuses on function names and disregards the importance of arguments. With this style, we concentrate on the data flow rather than the logic behind it. For beginners, Point-Free can be challenging to read or understand. But once you get used to it, you'll find it extremely useful.

Did you find this article helpful?
  • No

  • Neutral

  • Yes

Comments
DMCA.com Protection Status