The Single Argument Problem: Hello Unary!
Tags: javascript, webdev, tutorial, beginners
Published: 2020-01-13 14:11:04

_This is my first 2020 post on the DEV community and I have decided to share something really simple and possibly cool (depending on what you think of it). However, I do hope that you find it insightful._ 😜
___

In this post, I will explain, in less than 5 minutes, a problem I prefer to call the **Single Argument Problem** and how it manifests itself. Finally, I will share how it can be fixed, with special emphasis on the `unary()` helper function.

> _It is important at this point to note that all code snippets in this post are written in JavaScript. However, the concepts described in it may apply to several other programming languages. LET'S JUMP RIGHT IN 🚀🚀_

<br>

# Background

You are building a JavaScript application that requires an array of integers. However, there is no guarantee that you will always have an array of integers. So you decide to convert each element of every array to an integer before working with the array.

Based on your decision, you came up with this simple function:

```js
function getIntegerArray (arr) {
  return arr.map(parseInt);
}
```

The function effectively maps every element of the original array to a new array using the global `parseInt()` as the mapping function.

The `parseInt()` function is guaranteed to return an integer for a string that can be parsed into an integer, and `NaN` otherwise. You can learn more about how `parseInt()` works [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).

Then comes the moment of truth. You tested the `getIntegerArray()` function with an array like so:

```js
console.log(getIntegerArray(['1', '3', '5', '7', '9']));
// [1, NaN, NaN, NaN, NaN]
```

You were expecting to get this:
`[1, 3, 5, 7, 9]`

but instead you got:
`[1, NaN, NaN, NaN, NaN]`

**What could you have gotten wrong?** You'll find out as you read along.

<br>

# The Single Argument Problem

The mapping function passed to `Array.prototype.map()` has the following call signature:

```js
function mapFunction (element, index, arr, thisArg) { ... }
```

Hence, any function passed to `Array.prototype.map()` will be called with 4 arguments for every element in the target array.

In the case of your `getIntegerArray()` function, the mapping function is the global `parseInt()` function. Here, is kinda a breakdown of the function calls for each element of the array:

```js
parseInt('1', 0, ['1', '3', '5', '7', '9'], this) // 1st element
parseInt('3', 1, ['1', '3', '5', '7', '9'], this) // 2nd element
parseInt('5', 2, ['1', '3', '5', '7', '9'], this) // 3rd element
parseInt('7', 3, ['1', '3', '5', '7', '9'], this) // 4th element
parseInt('9', 4, ['1', '3', '5', '7', '9'], this) // 5th element
```

Since the global `parseInt()` function can only take 2 arguments, it discards the extraneous arguments like so:

```js
parseInt('1', 0) // 1st element
parseInt('3', 1) // 2nd element
parseInt('5', 2) // 3rd element
parseInt('7', 3) // 4th element
parseInt('9', 4) // 5th element
```

The second argument passed to the `parseInt()` function is taken to be the `fromRadix` of the string as first argument to be parsed.

So if the second argument to `parseInt()` is `0`, it is treated as though it was not passed; hence JavaScript determines the correct radix before parsing. You can learn more about how `parseInt()` works [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt).

If you execute the functions from before for each element of the array, here is what you'll get:

```js
parseInt('1', 0) // 1
parseInt('3', 1) // NaN
parseInt('5', 2) // NaN
parseInt('7', 3) // NaN
parseInt('9', 4) // NaN
```

which explains the result you got earlier. It appears that for your `getIntegerArray()` function to work as intended, the `parseInt()` mapping function will have to be called with only the first argument (effectively discarding all the other arguments).

This is what I will refer to as the **Single Argument Problem**.

<br>

# Fixing the Problem

Now that the problem have been identified, fixing it is only a matter of making some adjustments to the initial function to ensure that the `parseInt()` mapping function is called with only the first argument.

Here is the modified `getIntegerArray()` function:

```js
function getIntegerArray (arr) {
  return arr.map(x => parseInt(x));
}
```

A very simple modification and, Eureka!!! you fixed it 👍🏼. In fact, the arrow function syntax makes the modification more subtle in appearance that you might not even notice it.

Now you tested the `getIntegerArray()` function with the same array again and got the correct result you expected, like so:

```js
console.log(getIntegerArray(['1', '3', '5', '7', '9']));
// [1, 3, 5, 7, 9]
```

<br>

# Introducing the `unary()` helper function

The **Single Argument Problem** as described earlier is a very popular problem you might face when using callback functions in your applications. As a result, JavaScript utility libraries like Lodash (Underscore) provide a higher-order `_.unary()` helper function that can be used to create a new function (_that can be called with only one argument_) from an initial function.

Using this `unary()` helper function, the `getIntegerArray()` function can be modified as follows:

```js
function getIntegerArray (arr) {
  return arr.map(unary(parseInt));
}
```

Calling `unary(parseInt)` returns a new function that delegates its call to `parseInt()` but with only one argument. Hence, this effectively solves the Single Argument Problem for any use case.

Here is a simple implementation of the `unary()` function:

```js
function unary (fn) {
  if (typeof fn === 'function') {
    return function _unaryFn (firstArg) {
      return fn(firstArg);
    }
  }
  return fn;
}
```

A more compact version of the `unary()` function looks like this:

```js
function unary (fn) {
  return (typeof fn === 'function')
    ? firstArg => fn(firstArg)
    : fn;
}
```

<br>

# Final Words
That is all I have to say. Thanks for your patience and effort to make it to the end of this post. I hope you found it insightful.

**Please remember to:**
- Hit the **Like Button**
- Share with a Friend
- Follow me on **Twitter** ([@gladchinda](https://twitter.com/gladchinda))

Hope to see you again soon.

**_HAPPY CODING_**