Search code examples
javascriptnode.jsrecursionstack-overflowtail-recursion

Two recursive functions and stackoverflow errors in javascript/nodeJs. Understanding the differences


Looking into the SICP book and JS functional programming I created two recursive functions. My expectation was that both of them raised a stack overflow error. But it is only the sumAll() function that raised the error. See below the code for both functions sumAll() and factorial():

As expected the sumAll() function did raise a stack overflow error

function sumAll(n, i = 0, result = 0) {
  return (i > n)
    ? result
    : sumAll(n, i + 1, i + result);
}
    
console.log(sumAll(10000));

The factorial() function below did not raise a stack overflow error:

function factorial(n){
  return (n == 1)
    ? 1
    :  n* factorial((n-1))
}
    
console.log(factorial(10000))

My question is why the factorial() function does not raise a stack overflow and works perfectly in nodeJS meanwhile the sumAll() did raise it also in nodeJS


Solution

  • The number of local variables (i.e memory of local variables) is also considered in the call stack size.

    function computeMaxCallStackFrames(a, b, c, d) {
      try {
        return 1 + computeMaxCallStackFrames(a + 1, b + 1, c + 2, d + 3);
      } catch (e) {
        // Call stack overflow
        // console.log(e);
        return 1;
      }
    }
    var stackFrames = computeMaxCallStackFrames(1, 4, 6, 2);
    console.log(stackFrames);

    try increasing the no. of parameters, you'll see the decrease in number of recursion calls / call stack frames.

    function computeMaxCallStackFrames(a, b, c, d, e) {
      try {
        return 1 + computeMaxCallStackFrames(a + 1, b + 1, c + 2, d + 3, e-2);
      } catch (e) {
        // Call stack overflow
        // console.log(e);
        return 1;
      }
    }
    var stackFrames = computeMaxCallStackFrames(1, 4, 6, 2, 9);
    console.log(stackFrames);

    with zero local variables.

    function computeMaxCallStackFrames() {
      try {
        return 1 + computeMaxCallStackFrames();
      } catch (e) {
        // Call stack overflow
        // console.log(e);
        return 1;
      }
    }
    var stackFrames = computeMaxCallStackFrames();
    console.log(stackFrames);

    So, we can clearly see that the number of local variables (i.e memory of local variables) is also considered in the call stack size. If there are many local variables then the no. of recursive calls will be less.

    Edit: And we all know the stack size will vary from browser to browser. So the output will not be same in different browsers, but it should be consistent in the same browser even if we run it multiple times.

    Hope it all makes sense now.