Variable length currying in JavaScript
Tags: javascript, beginners, webdev, algorithms
Published: 2019-06-05 23:44:47

This is an interesting programming challenge that reddit user `i7_leaf` claims to have received as [an interview question](https://www.reddit.com/r/javascript/comments/9vxdkx/was_asked_this_js_interview_question_is_this_even/).

# Preface ⭐

There is one key difference between the original question and what I will cover in this article. The interview question asked the candidate to write a function that executes as follows:

```javascript
addSubtract(1)(2)(3);          // 1 + 2 - 3             = 0
addSubtract(1)(2)(3)(4)(5)(6); // 1 + 2 - 3 + 4 - 5 + 6 = 5
```

It is worth noting that this curried function does not end in any sort of delimiter, e.g. a terminating method `.execute()` or empty parameter `()`. What makes this challenge both difficult and interesting is the lack of signal that “this is the last digit in the sequence.”

I agree with the majority of comments in the discussion thread that the interviewer did not mean to ask this question _per se_. As postulated, this function cannot exist. It is impossible for `addSubtract(1)(2)(3)` to both be a primitive (the number 0 in the first example) and a function (that accepts 4 as a parameter in the second example).

That said, this is _conceptually_ possible with a very slight tweak. While the following two statements _cannot both_ be true, the third statement _can_.

```javascript
// This cannot be true with the following statement.
addSubtract(1)(2)(3) === 0;

// This cannot be true with the preceding statement.
addSubtract(1)(2)(3)(4)(5)(6) === 5;

// This can be true:
addSubtract(1)(2)(3) + addSubtract(1)(2)(3)(4)(5)(6) === 5;

// These can be true too:
+addSubtract(1)(2)(3) === 0;
+addSubtract(1)(2)(3)(4)(5)(6) === 5;
```

I believe the interviewer was actually testing the candidate’s ability to write a curried function that alternates add and subtract operations, but innocently did not realize the two function examples were mutually exclusive. The scenario in the third statement is such an obscure functionality of JavaScript that I do not support its use as an interview question. It’s a “think outside the box” solution, but not a _practical_ one.

# How does it work? 🤔

Any object can be type cast to a string or number using built-in methods.

The use of `+` in the third example attempts to type cast both sides of the argument to a `Number` type. If there is no way to type cast to a `Number` type, it will attempt to typecast to a `String` type (the same way `'Hello ' + 123 === 'Hello 123'`). It is because of our ability to explicitly define how to type cast an object that we are able to solve the problem of `addSubtract(1)(2)(3) + addSubtract(1)(2)(3)(4)(5)(6)`, and it is because of JavaScript lack of type casting when calling the object by itself that it cannot know that `addSubtract(1)(2)(3)` is the primitive `0`. It is, in fact, not the primitive number `0`. It is a function, which is why we can both treat it as an object able to be type cast and call it as a function:

```javascript
const x = addSubtract(1)(2)(3); // function
+x;    // type cast to 0
+x(4); // type cast to 4
```

When treating an object (or function) as a number, the `valueOf` method of that object will be called, the return value of which is what is used for the numerical operation. When treating an object as a string, the `toString` method of that object will be called.

```javascript
const myStrObject = {
  toString: function() {
    return 'Str';
  }
};
console.log('My object is ' + myStrObject); // 'My object is Str'
console.log(myStrObject + 297);             // 'Str297'

const myNumObject = {
  valueOf: function() {
    return 123;
  }
};
console.log('My object is ' + myNumObject); // 'My object is 123'
console.log(myNumObject + 297);             // 420
```

# Let’s curry 🍛

That’s really all the introduction you need to solve this problem, so I’ll provide the solution.

```javascript
// Given an array of numbers, if the index is even, add.
//   If the index is odd, subtract.
const addSubtractReducer = (total, current, index) =>
  (index % 2) === 0 ?
    total + current :
    total - current;

const addSubtract = x => {
  const nums = [ ];

  // Recursive function that accumulates numbers for the operation.
  const f = y => {
    nums.push(y);
    return f;
  };

  // When the recursive function is type cast to a number,
  //   reduce the accumulated numbers.
  f.valueOf = () => {
    return nums.reduce(addSubtractReducer, x);
  };

  // Return the recursive function, having added the first digit.
  return f;
};
```

I defined the reducer function outside of the main function for readability. You may prefer including it in the function for better encapsulation.

The reducer merely alternates addition and subtraction. Given a running total and a new number, if it’s an even index, add; if it’s an odd index, subtract.

The recursive function `f` is used to curry parameters. Every function call to `f` just returns `f`, allowing you to call it ad nauseum, each time adding the new parameter to the array of numbers that we will add/subtract.

The function `f` has a `valueOf` property. When we type cast `f` to a number, this property will get called. Starting with the first provided number (`x`), this `valueOf` property reducers the remaining numbers using the aforementioned alternating operations.

The first call to `addSubtract` then returns the recursive function `f` after having created it.

# Limitations 🙅

In typical interview fashion, this solution is not perfect. If an interviewer were to grill you about limitations, this has weird behaviors when caching the return value of any of the function calls. Each function call beyond the first call to `addSubtract` will be using the same array of `nums`. This may cause unintended behavior.

```javascript
const addTo1 = addSub(1); // nums = [1]
+addTo1(2); // 3             nums = [ 1, 2 ]
+addTo1(2); // 1             nums = [ 1, 2, 2 ]
```

The `nums` array is stored inside `addTo1`. The first call adds 2 to the value. The second call subtracts 2 from the value. This can be resolved by returning a new instance of an array for each function call. The original interview question did not stipulate this as a requirement, so I opted to provide the solution with less code complexity.

# Conclusion 🔚

I loved the obscurity of this problem, and users seemed to enjoy my solution. I decided I would share out of love for JavaScript language. If you are an interviewer, _do not_ ask this question during interviews. Make sure your curried examples have the same number of parameters or a terminating method. As a JavaScript expert, I do not believe this is a good interview question for JavaScript comprehension. This knowledge makes for a good puzzle, but not for a better developer. If you are an interviewee, do not expect this during an interview. Ask the interviewer for clarification on the different parameter lengths. It was probably a mistake on their part. (If it wasn’t, at least now you know how to solve it!)

If you liked this article, feel free to give it a heart or a unicorn. It’s quick, it’s easy, and it’s free! If you have any questions or relevant insight, please leave a comment.

To read more of my columns or contact me, you can find me on [LinkedIn](https://www.linkedin.com/in/charles-stover), [Medium](https://medium.com/@Charles_Stover), and [Twitter](https://twitter.com/CharlesStover), or [check out my portfolio on CharlesStover.com](https://charlesstover.com/).