Point-free gotchas in JavaScript
Tags: javascript, functional, codingstyle, pointfree
Published: 2018-02-26 10:41:48

---
title: Point-free gotchas in JavaScript
published: true
description: Some of the possible problems with point-free style in JavaScript.
tags: JavaScript, FP, coding style, point-free
---
*Note: this [post](https://medium.com/@DanHomola/point-free-gotchas-in-javascript-d5c1f8fa5391) was originally published on [my Medium profile](https://medium.com/@DanHomola)*

I am a big fan of functional programming, I enjoy the conciseness of it and it fits my way of thinking better. I also like clean code with as few redundancies as possible. Having said that, it should come as no surprise that point-free (sometimes also called tacit) style appeals to me. Over the last few days I came across several gotchas when applying this style in JavaScript and decided to write them down.

## What is point-free style

As [Wikipedia states](https://en.wikipedia.org/wiki/Tacit_programming):

> [Point-free] is a programming paradigm in which function definitions do not identify the arguments (or "points") on which they operate.

This may seem weird at first, but let's use a simple example. Assume we have a function that takes a string and returns that string with the first letter capitalised. Next, we have an array of strings that we all want to capitalise. This is a simple use case for the [`map` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map):

```js
const capitalise = str =>
    str && str.charAt(0).toLocaleUpperCase() + str.substr(1);

const words = ["foo", "bar", "baz"];

// logs [ 'Foo', 'Bar', 'Baz' ]
console.log(words.map(w => capitalise(w)));
// logs [ 'Foo', 'Bar', 'Baz' ]
console.log(words.map(capitalise));
```

Notice the second `map` use, it does not state the name of the argument and does not create a new function. The reason this works is that `map` calls its first argument as a function taking three arguments:

* the item of the array to process (this is the only mandatory parameter),
* the index of that item,
* the whole array being processed

Out `capitalise` function happens to also take the item to be processed as its first (and only) argument and so it works when used point-free in this case.

There are more uses for this style and we will see them as we go through the article.

## Gotcha #1: Function taking more parameters than you expected

The first gotcha comes from the fact that you can call a function in JavaScript with as many arguments you want – be it too few or too many.

In case you provide too few arguments, those you haven't provided are set to their default value (which is `undefined` unless otherwise specified).

In case you provide too many arguments, the function ignores the excessive ones (unless it uses the [`arguments` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments)).

This is probably not new to you, in the context of point-free it can lead to some unexpected results, though.

Let's take the simplest of examples: write a function that takes an array of strings and returns the numeric values of the items. For the sake of an example we assume the input is correct. Simple enough, there is [`Number.parseFloat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseFloat) for that:

```js
const nums = ["25", "45", "11"];
// logs [ 25, 45, 11 ]
console.log(nums.map(num => Number.parseFloat(num)));
// logs [ 25, 45, 11 ]
console.log(nums.map(Number.parseFloat));
```

As we can see, the point-free version works like a charm.

Well, what if someone told us the numbers are always integers and we don't have to parse them as floats? Then we would swap the `Number.parseFloat` for the [`Number.parseInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseInt), right?

```js
// logs [ 25, 45, 11 ]
console.log(nums.map(num => Number.parseInt(num)));
// logs [ 25, NaN, 3 ]
console.log(nums.map(Number.parseInt));
```

Whoa, what is that? The point-free version behaves rather strange all of a sudden.

The reason for this is that while `Number.parseFloat` only takes one argument – the string to parse – `Number.parseInt` takes an additional optional argument – the radix of the number to be output (for example 16 for hexadecimal strings). Thus when used in a map like that this is what actually happens:

```js
console.log(nums.map((item, index, array) =>
    Number.parseInt(/* string: */item, /* radix: */index, array)));
```

As we can see the radix argument of `Number.parseInt` is set using the index of the current item. That explains the `3` output for the `11` input as 3 is 11 in binary.

This is the first type of issue that can arise from point-free in JavaScript: functions taking more arguments than you expect.

There is no fool-proof way to protect yourself against this other than using point-free only with functions you know the signature of and know are not going to change, otherwise your code can break unexpectedly.

## Gotcha #2: Unexpected `this`

This one popped up in a job interview I took not too long ago:

```js
const obj = {
    message: "Hello",
    getMessage() {
        console.log(this.message);
    },
};

// Broken
setTimeout(obj.getMessage, 0);
```

The question was to fix the error.

One would probably expect `"Hello"` to be output (I know I did). Yet, `undefined` is output to the console.

The reason for this is the way `setTimeout` executes the callback function. The [callback is executed in a different execution context](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) and if `this` is not set explicitly, it will be set to the `global` object. And as `global` (or `window` if run in browser) does not have a `message` member our example prints `undefied`.

There are two way to fix this:

```js
// Fix A - closure
setTimeout(() => obj.getMessage(), 0);
// Fix B - binding
setTimeout(obj.getMessage.bind(obj), 0);
```

The first one uses a closure to *implicitly* set `this` of the `getMessage` call to the proper value.

The second (point-free) one makes use of the [bind method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) to set the value of `this` *explicitly*.

There is another example of a code that seems to be alright – simple regular pattern use:

```js
const isActivationCode = /^\d{4}-\d{4}-\d{4}$/.test;
console.log(isActivationCode("1234-5678-1234"));
```

However this ends up throwing a `TypeError` saying:

> `Method RegExp.prototype.test called on incompatible receiver undefined`

or a bit more helpfully in Safari:

> `RegExp.prototype.test requires that |this| be an Object`

Again, the problem is that `this` has an unexpected value (in this case `undefined`). The solutions are the same as in the previous case:

```js
// Fix A - closure
const isActivationCodeClosure = code => /^\d{4}-\d{4}-\d{4}$/.test(code);

// Fix B - binding
const regex = /^\d{4}-\d{4}-\d{4}$/;
const isActivationCodePointFree = regex.test.bind(regex);

// logs true
console.log(isActivationCodeClosure("1234-5678-1234"));
// logs true
console.log(isActivationCodePointFree("1234-5678-1234"));
```

The point to take here is that if the function you want to call point-free makes use of `this`, you should be very aware that it is set to what you expect.

## Conclusion

As much as point-free style is useful in other (functional) languages, in JavaScript it often brings problems that might not be worth the conciseness it brings. I still use it sometimes when the function called is under my control. After these experiences I will be more careful with it, though.