Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing constants in a recursive function [closed]

I'm refactoring some code and wondering what pattern is least memory intensive and easiest to read when it comes to passing constants in a recursive function.

For example, I could just pass each constant down to the next recursive function, but it isn't obvious that those params are constants:

const startFoo = (myArray, isFoo, isBar) => {
  console.log(isFoo, isBar);
  startFoo(myArray, isFoo, isBar);
};

Alternatively, I could have 2 functions and keep constants in the closure of the first, but I'm curious if recreating the second function every time the first is called will cause unnecessary object creation & GC:

const startFoo = (myArray, isFoo, isBar) => {
  const foo = myArray => {
    console.log(isFoo, isBar);
    foo(myArray);
  };
  foo(myArray);
};

Finally, I could keep it at one function, and just cache the initial values:

const startFoo = (myArray, isFoo, isBar) => {
  if (!startFoo.cache) {
    startFoo.cache = {
      isFoo,
      isBar
    }
  }
  const {isFoo, isBar} = startFoo.cache;
  console.log(isFoo, isBar);
  startFoo(myArray);
};

All 3 look like they'll be good candidates for the upcoming (here-ish) TCO so I don't see that playing into the decision, but if it does that'd be good to know as well!

like image 416
Matt K Avatar asked Jun 13 '16 13:06

Matt K


People also ask

What happens when a recursive function does not have a proper exit condition?

Incase base condition or exit condition is not specified in the function then recursive calls to the function can lead to an infinite loop.

What are the four fundamental rules of recursion?

Like the robots of Asimov, all recursive algorithms must obey three important laws: A recursive algorithm must call itself, recursively. A recursive algorithm must have a base case. A recursive algorithm must change its state and move toward the base case.

Will a recursive function without an end condition ever quit?

Absolutely, yes. Tree evaluators are almost always written as sets of recursive functions.


Video Answer


1 Answers

it isn't obvious that those params are constants

Does it matter that much? If you are choosing recursion over a loop because you like the functional approach, all your variables and parameters are constants anyway. You can tell whether they stay constant or not in the recursive descent by looking at the recursive call and comparing the arguments to your function's parameters.

Alternatively, I could have 2 functions and keep constants in the closure of the first, but I'm curious if recreating the second function every time the first is called will cause unnecessary object creation & GC.

Unlikely. Afaik, no function objects are instantiated for simple inline helper functions that are never used as an object or exported as a closure. At least it's a rather trivial optimisation, and even when not done the GC pressure will not be hard or impair performance noticeably.
You should go for this approach as it is the cleanest and most maintainable.

I could keep it at one function, and just cache the initial values

You better not do that. It introduces an extra condition in the function that will impair performance because it is executed on each and every call, but most of all it complicates the code unnecessarily much. This is also likely the reason for the bug you introduced - you never unset the .cache in the base case1 so that all invocations will use the same constants no matter what is passed to them. Also, you are leaking the constants into the global scope where anyone could access them.

1: Admittedly, your demo function does not have a base case, but ask yourself: if you had added one, would you have forgotten to unset the cache?

like image 142
Bergi Avatar answered Sep 28 '22 07:09

Bergi