-2

The function below checks whether a number is even or odd - simple. My question is regarding the call stack. To make sure I understand it.

Is the second else if statement (number<0) calling the main function isEven(number) so it runs again from top checking if number==0 and so on?
Is it recursion?

function isEven(number) {
  if (number == 0) 
    return true;
  else if (number == 1) 
    return false;
  else if (number<0) {
    number*=-1
    return isEven(number)
  }
  else 
    return isEven(number-2)
};


console.log(isEven(50));
// → true
console.log(isEven(75));
// → false
console.log(isEven(-1));
// → false
TheNoob
  • 9
  • 3
  • Open the browser's developer tools (F12), set a breakpoint at the first statement in your function, run it and find out. That said, there is literally *tons and tons* of reading material on recursion (in JavaScript and any other language) available, I strongly suggest reading more about it first. It's not nice to ask people to write up yet another introduction just for you when countless introductions are available already. – Tomalak Oct 31 '15 at 10:32
  • Tomalak - I did not ask anybody to write another introduction about recursion and I read a couple of posts about it. As you can probably see, by the level of my question, I am learning so opening developer tools and setting breakpoints is something that I am not aware of. If I would be I would have done it instead of asking questions here. What is not nice is being impolite for people that are asking questions on a guess what? Web forum which is for people who ask questions. – TheNoob Oct 31 '15 at 10:54
  • I am not being impolite, quite the opposite. I have made a suggestion to you. As you can probably see, if even the developer tools are new to you, then you are at the *very beginning*, and recursion might be quite a bit out of scope for your current level. In any case, my point stands: You are asking that people explain a basic concept to you, a concept that thousands of explanations and tutorials have been written about. A concept you clearly have not read enough about so far. This website is for asking questions *when you are stuck*, and that means you must do your research *first*. – Tomalak Oct 31 '15 at 10:58
  • Compare: [How much research effort is expected of Stack Overflow users?](http://meta.stackoverflow.com/q/261592/18771) and http://stackoverflow.com/help/how-to-ask – Tomalak Oct 31 '15 at 11:01
  • Perhaps you don't know about developer tools, but in that case you should make it a top priority to learn about them before doing anything else. But I assume you know you to use Google, with which you could have found this in Wikipedia: "Recursion is the process a procedure goes through when **one of the steps of the procedure involves invoking the procedure itself**." –  Oct 31 '15 at 11:05
  • @MaciejW You will find that Tomalak is espousing a commonly held view. That said, I disagree with him. You should feel free to ask any on-topic question you like. There is often something for everyone to learn in the answers to even well understood questions. Best not to to engage your critics in this instance and continue with your research. – Ben Aston Oct 31 '15 at 11:06
  • Tomalak - I wanted just yes or no answer :) to prove that I understand what is going on. This is an exercise from Eloquent Javascript Book - Chapter 3. Developer tools aren't a new concept to me, just the use of setting breakpoints is. Anyway thanks for the suggestion of checking dev tools :) Have a great weekend! – TheNoob Oct 31 '15 at 11:06
  • #BenAston - thanks :) – TheNoob Oct 31 '15 at 11:09
  • @BenAston Sorry, when "search & research" is on page 1, paragraph 1 in the FAQ then no, it's not "a commonly held view" that is somewhat debatable, then it is a house rule. – Tomalak Oct 31 '15 at 11:09
  • @torazaburo - assuming that everybody can use Google, probably 90% of this forum should be deleted because everybody can use Google or find their answers in books related to Javascript, PHP and Perl or read Documentation:) According to Stack Overflow rules which were mentioned - my question is not general, I provided a sample of code and asked a question which is related to how a code works. – TheNoob Oct 31 '15 at 11:17
  • It's funny that someone is so angry that I asked a simple and not challenging question, which I proved that is relevant, and down voted it :) – TheNoob Oct 31 '15 at 11:27
  • *"my question is not general, I provided a sample of code and asked a question which is related to how a code works"* That's all true, but still you did not do enough research, and that was actually the only point that I criticized. Indulge me and read the mouseover text that appears when you hover over the "downvote" button. – Tomalak Oct 31 '15 at 11:35
  • *Probably 90% of this forum should be deleted*. You're right. Of course, you can use Google to find answers already here as well, in addition to using SO's own search feature. If you had Googled for "what is recursion", the first answer would have been this one: http://stackoverflow.com/questions/3021/what-is-recursion-and-when-should-i-use-it. –  Oct 31 '15 at 11:36
  • 1
    @BenAston Yes, "you can feel free to ask any on-topic question you want", as long as you are OK with the fact that others can then feel free to downvote it and vote to close it. In this case, whether or not this question is "on-topic" is borderline, being as it is primarily a "how does this code work" or "is this an example of XX" question. To the OP, do not confuse downvoting with "being angry". People downvote because they care--they care that the site be populated with useful, helpful, non-duplicative questions. –  Oct 31 '15 at 11:46

6 Answers6

2

Is the second else if statement (number<0) calling the main function isEven(number) so it runs again from top checking if number==0 and so on?

Yes, that's right.

Is it recursion?

Yes, it is an example of how recursion works.

It's not a very good example though, as it can easily be rewritten to use a loop instead (or even just a single expression), so it doesn't show the advantages of recursion.


To better show how recursion works the function could split the number in half and call itself on each half:

function isEven(number) {
  if (number == 0) {
    return true;
  } else if (number == 1) {
    return false;
  } else if (number < 0) {
    return isEven(-number);
  } else {
    // split number in two halves
    var a = Math.floor(number / 2);
    var b = number - a;
    // number is even if the halves have the same status
    return isEven(a) == isEven(b);
  }
}

This will split the work in half and call itself to do the work of each half. It will turn the work into smaller and smaller parts until each part is the trivial work of determining if 0 or 1 is even.

By splitting the work in half instead of shaving off a small portion, the parts quickly get smaller. Calling isEven(10000) with this implementation will only make calls 13 levels deep, while the implemtnation in the original example would make calls 5000 levels deep.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
0

Yes, works as you expect.

And yes, that is recursion. As is the one in the last else statement.

Please note that many advise to use recursion as the last statement, so you could rewrite it like that:

function isEven(number) {
  if(number < 0)
     number *= -1

  if (number == 0) 
    return true;
  else if (number == 1) 
    return false;
  else 
    return isEven(number-2)
};
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Stefano Cazzola
  • 1,597
  • 1
  • 20
  • 36
0

You can see it's recursion because your function has a stop criteria (actually two of them, number==0 and number==1),and then calls itself. It's a very basic example of recursive function.

ivcandela
  • 331
  • 3
  • 12
0

Is it recursion?

Yes, it is indeed.

0

The second condition is to support negative numbers. I would have put that on its own:

function isEven(number) {
  return isPositiveEven( number < 0 ? 
                         number*-1 : 
                         number ); 
};

Now isPositiveEven could look like this since we never have negative numbers:

function isPositiveEven(number) {
  if (number == 0) 
    return true;
  else if (number == 1) 
    return false;
  else
    return isEven(number-2)
}

How it works is that we know the evenness of 0 and 1 and it the number you provide is higher we know it has to be 2 or higher and can recurse with the same minus two since it will not change the odd/even property. Eg. isPositiveEven(3) will turn into isPositiveEven(1) and will hit the base case and return false. For isPositiveEven(2) it will turn into isPositiveEven(0) and will hit the base case and return true.

It's tail recursive, which means recursion is not really needed to do this. The same function written in terms of loops can look like this:

function isEven(number) {
  var n = number < 0 ? -1*number : number; // Math.abs(number)
  while( n > 1 ) {                         // n %= 2
    n -= 2;
  }
  return n == 0;
}

The while loop is actual a modulus operation and JavaScript has the operator % which works for negative numbers as well -10 % 2 === 0 thus this can be written as simple as:

function isEven(number) {
  return number % 2 === 0;
}
Sylwester
  • 47,942
  • 4
  • 47
  • 79
0

Yes, your example is recursive.

Any function that contains a reachable invocation of itself is recursive.

Recursion like this is leveraging the recursive function invocation feature of JavaScript.

Before ALGOL-60 in 1960 (although Lisp was defined around that time, its compiler came later), languages did not support convenient user-land recursion for two reasons:

First, early languages were register-based. Subroutine instructions would save the current memory location in the jump address, and then set the program counter to the next address. This was simpler than maintaining a stack, but it meant the programmer had to effectively implement their own recursion inside the language. When stack-based languages were introduced, recursion became easier.

Second, it was seen as being computationally expensive to achieve (and CPUs were pretty weedy back then).

JavaScript is an example of a stack-based language (as most (all?) modern languages are).

This means that the location in the execution of your program is defined by a stack data structure. The stack was chosen for this task because it offers the required last-in first-out (LIFO) behavior needed for nested subroutine calls.

The items on the stack are called stack frames or simply frames (sometimes they are called activation records) and they correspond to invoked subroutines in your program (the top frame being current). Each frame contains metadata associated with the subroutine call, and this varies with each language.

In JavaScript stack frames are called Execution Contexts, and the EcmaScript specification defines the metadata they contain.

In your example:

01    function isEven(number) {
02       if (number == 0) 
03         return true;
04       else if (number == 1) 
05         return false;
06       else if (number<0) {
07         number*=-1
08         return isEven(number)
09       }
10       else 
11         return isEven(number-2)
12    };
13
14    console.log(isEven(2)); // 2 chosen for simplicity.

// >> << indicates the currently executing expression.

          Expression           |      Current stack
--------------------------------------------------------
14 console.log(>>isEven(2)<<); |   [
                               |     { fn: global, arguments: [], ... }
                               |   ]
11 return >>isEven(0)<<;       |   [
                               |     { fn: isEven, arguments: [2], ... },
                               |     { fn: global, arguments: [], ... }
                               |   ]
03 >>return true<<;            |   [
                               |     { fn: isEven, arguments: [0], ... },
                               |     { fn: isEven, arguments: [2], ... },
                               |     { fn: global, arguments: [], ... }
                               |   ]
11 >>return isEven(0)<<;       |   [
                               |     { fn: isEven, arguments: [2], ... },
                               |     { fn: global, arguments: [], ... }
                               |   ]
14 >>console.log(isEven(2));<< |   [
                               |     { fn: global, arguments: [], ... }
                               |   ]
   >>end of program<<          |   [
                               |   ]
Ben Aston
  • 53,718
  • 65
  • 205
  • 331