The problem with Higher Order Array Functions (js)
Tags: javascript, react, functionalreactiveprogramming, node
Published: 2023-08-15 05:26:36

## So What are higher order functions ?
Higher order functions are functions which accepts an argument as a function or a function which returns another function. In JS we use lot of HOF(Higher Order function) and functional programming patterns. some examples

> I'm using use the term `functions` interchangeably with `methods`

**Function accepting callback function**
Array.map, Array.filter, Array.reduce

**Function returning function**
Function.apply, Function.call, Function.bind 
  
## Use cases 
Functional programming patterns provide easier expressive way to write code. Using Array methods helps us a lot by not writing a for loop statements by ourselves.

_Array Methods_
``` js
const nums = [2,4,6];

// map
const squred = nums.map( (num) => num**2);

// filter (only even numbers)
const evenNums = nums.map ( num => num%2 == 0);

```

_For loops_

```js
const nums = [2, 4, 6];
const squared = [];
const evenNums = [];

// map
for (let i = 0; i < nums.length; i++) {
  squared.push(nums[i] ** 2);
}

// filter (only even numbers)
for (let i = 0; i < nums.length; i++) {
  if (nums[i] % 2 === 0) {
    evenNums.push(nums[i]);
  }
}
```

Array Methods provide a easier way to create a new object with .map method and with filter we can create a new array with desired elements 

Array methods returns themselves(Array object), Allowing us to chain them with multiple methods.

``` js
const nums = [2,4,6,10];
// square all numbers and then sum them
const result = nums.map( (num) => num**2 ).reduce((prev,curr) => prev+curr,0)
```
In the above code sample combining array methods and arrow function allows us to perform lot of operations in single line.

Obviously, it is more expressive and readable than traditional loops.

## So What are my Concerns

My concerns raised whenever I'm chaining array methods. Chaining Array methods looks good to our eyes but not to the JS Garbage collector.

Let's tackle a simple problem. We have an array of numbers representing people's incomes. Our job is to calculate a 5% tax on incomes that are above 500 and then create a new array containing those incomes along with their corresponding taxes only.

```js

const incomes = [200,300,600,800];
 
const output = incomes.filter((income) => income > 500).map((income) => (income * 5 / 100) + income);

console.log(output); // [ 630, 840 ]
```

The above is the straightforward implementation. but we miss out the fact that to get the desired output we loop through the whole array twice and an intermediate array is also created. 

![Image of output arary](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gowzxuqr82y7evcu78u6.png)

So algorithmically speaking as we loop through the array twice the algorithmic complexity is O(2*n) and That filtered array(intermediate) array has to be garbage collected by the v8.

## What can be done

Chaining Array methods with smaller arrays will not cause much of performance impact. but when doing those with larger arrays we can write traditional loops instead of array methods, so that we don't have to loop through multiple arrays.

```js
const incomes = [200,300,600,800];
const result = []
for (let i = 0; i < incomes.length; i ++){
    if (incomes[i] > 500){
        const withTax = incomes[i] + (incomes[i] * 5 /100)
        result.push(withTax);
    }
}
console.log(result); //[ 630, 840 ]
```

in the above we are processing only the incomes above 500 and just pushing them to result array. Of course, this looks little longer than the array methods implementation.

we can use `for(of)` loops or `.foreach()`  to make it little nicer.

## So is this the perfect implementation ?

This approach appears to be a good one. However, there is a potential issue with this code in the following line: 


```js
        result.push(withTax);
```

The `.push` method is used to add elements to an array, but internally, the JavaScript engine needs to make memory allocation calls to the operating system to allocate memory for the array. Making multiple operating system calls can be an expensive task, and this is abstracted by the `.push` method.
 
So, this should hold true for the `.map` implementation. But it's not the same. When we call the `.map` method on an array and the output array is going to end up with the same size, the V8 engine actually makes just one memory allocation call for the entire array.

## Conclusion
so which is the faster way, It's always better to use HOF's if we are not chaining multiple methods. but I can't answer whether chaining multiple array methods or dynamically pushing elements into an array is faster. that might require multiple benchmarks and analysis.

I apologize if I made any grammatical mistakes.