Caveats around point-free functions
Tags: javascript, functional, webdev
Published: 2020-04-09 18:54:08

Functional programming is all the rage in JavaScript these(last 2 years?) days and for all the good reasons. I like how functional programming concepts are simple to implement, yet powerful in JavaScript. Once such concept, I'd like to discuss is `point-free` style.

## What is `point-free` ?
The idea is simple enough. Instead of using arbitrary variable names for function parameters only to pass them to another function as arguments, you just skip them.

Example:

```js
const isGreaterThan5 = x => x > 5

// instead of 
let numbersGreaterThan5 = numbers.filter(number => isGreaterThan5(number))

// use point-free
let numbersGreaterThan5 = numbers.filter(isGreaterThan5)
```

> "Point-free style — aims to reduce some of the visual clutter by removing unnecessary parameter-argument mapping." - Kyle Simpson 

Point-free style is great. It is easy to adopt and really addictive once you get used to it. However, consider the following snippet

```js
fetchUsers().catch(Raven.captureExeception)
```

Here `Raven` is [Sentry's NodeJs SDK](https://www.npmjs.com/package/raven). You would expect this to work, as the `err` argument to the callback passed to catch will be passed to `Raven.captureExeception`. However, if you would try that you'd get

```
Cannot read property 'generateEventId' of undefined
```
So what went wrong? `this`. 

If you remember your JavaScript correctly, you should know what to expect here:
```js
const obj = {
  log () {
    console.log(this)
  }
}

const x = obj.log

obj.log() // logs: obj { ... }
x() // logs: window (or the global in environment)
```

Same thing happens when you try to use point-free style. Since `.captureExeception` is not called off `Raven` object, `this` inside `.captureExeception` will not refer to `Raven`, but the global and hence the error. You can check the [source code here](https://github.com/getsentry/raven-node/blob/6dbb5ef37ccd536360d5f73b601a42faee23b2f4/lib/client.js#L407).

<mark>Lesson #1: Object-Oriented Programming and Functional programming don't mix well.</mark> 
Before you jump at me for drawing such over generalized conclusions. This is just what I've found in my brief experience, yours may differ and if it is, I'd like to read about it.

Next, we have a naive use case

```js
const numbersValues = ["1", "2", "3"]
const numbers = numbersValues.map(parseInt) 
numbers // Outputs: [1, NaN, NaN]
```
You probably know what happened here. But since it is so easy and tempting to make such mistake, I'll explain. If you pull the documentation for `.map` and `parseInt` on MDN, you'll find the following syntax:

```js
// Array.prototype.map
let new_array = arr.map(function callback( currentValue[, index[, array]]) {
    // return element for new_array
}[, thisArg])

// Syntax for parseInt
parseInt(string [, radix])
```
You'll quickly realize what is happening here, the `index` for each element is being passed to `parseInt()` as the second argument causing the `currentValue` to be parsed to int but in radix = `index`. Since "3" in not a valid number `radix 2`(binary), we get NaN.

<mark>Lesson #2: You must be certain of both the arity and signature(s) of concerned functions when using point-free.
</mark> 


## That's it folks!
I'll be interested in reading through more such caveats, please share them!. I work with Node, Postgres, Ember and Vue. Hit me up if you want to discuss something interesting related to these.