Explanation for the given example for Replace Loops with Recursion

Tell us what’s happening:
Describe your issue in detail here.

Unfortunately, my issue is with the lesson itself, and how it’s very unclear and inadequate, especially for a concept that is a bit mind-boggling to come across for the first time (A function that calls itself???).

First line:
“Recursion is the concept that a function can be expressed in terms of itself.”

This very first line is already a bit iffy. I’ve seen this described more simply and clearly in a few places:

“In its simplest form, a recursive function is one that calls itself.” As explained by Beau Carnes

" Recursion is when a function calls itself until someone stops it. If no one stops it then it’ll recurse (call itself) forever." As explained by Yazeed Bzadough

"In the most basic of terms, recursion is when a function keeps calling itself until it doesn’t have to anymore. " As explained by Joel P. Mugalu

" A recursive function is a function that calls itself until it doesn’t. And this technique is called recursion." From javascripttutorial.net

IMO, these articles are pretty good at providing a much clearer, more detailed explanation of what recursion and recursive functions are, and maybe even critical to actually understanding the concept.

Going back to it, this following bit is from the lesson itself…

Using a for loop, you could do this:

  function multiply(arr, n) {
    let product = 1;
    for (let i = 0; i < n; i++) {
      product *= arr[i];
    }
    return product;
  }

Ok, I understand this, this builds upon what we’ve learned from previous lessons.

And product must == 1 because it needs to start off the 1st item/number in the array (arr[0]).
So that whether it’s 1 or 5 or 10 or 57, the first number multiplied by 1 is itself,
before we move on to *= and the next number in the array.

But then going from the example using the for loop, the next line makes no sense whatsoever to a beginner unfamiliar with recursion:

" However, notice that multiply(arr, n) == multiply(arr, n - 1) * arr[n - 1]"

How in the world would I ever notice this?? It seems completely arbitrary. How does it make any sense to suddenly go from the for loop example to this line with no break down of why ‘multiply(arr, n)’ is equivalent to ‘multiply(arr, n - 1) * arr[n - 1]’ and how we came to this conclusion?

(I hate this. it’s like when they tell you in school to just memorize formulas without ever proving or explaining why they work. “Just accept what I tell you, you don’t need to know why.” Pretty sure that’s not why anyone gets into programming.)

If I substitute an actual array and number for n, for e.g.:

arr == [1, 2, 3, 4, 5] and n == 3, it begins to make some sense.

Step by step, this translates to:

Step 1: multiply(arr, n) == multiply(arr, n - 1) * arr[n - 1]
Step 2: multiply([1, 2, 3, 4, 5], 3) == multiply([1,2,3,4,5], 3-1) * arr[3-1]
Step 3: multiply([1, 2, 3, 4, 5], 3) == multiply([1,2,3,4,5], 2) * arr[2]
Step 4: translated to human: multiply first 3 numbers of array [1, 2, 3, 4, 5] == multiply first 2 numbers of array [1, 2, 3, 4, 5] * 3rd item of array
Step 5: Ok yes, now I can see they are equivalent.

(Still no idea how this was deduced in the first place though. I’d like to know how the first person who came up with this did so. Mind-boggled)

Next, here’s the given code example following that very confusing, unclear declaration:

  function multiply(arr, n) {
    if (n <= 0) {
      return 1;
    } else {
      return multiply(arr, n - 1) * arr[n - 1];
    }
  }

For the base case, why do you return 1 if n <= 0?

Why not return 0 since if the given n is 0 or less than 0, that would mean the instruction would be to multiply the first 0 (or less than 0) numbers in the array?

And isn’t the basic math that anything multiplied by 0 equals to 0?

This made it way more confusing for me.

IMO, I think this is the reason recursion (and anything else with a similar issue) is confusing because it’s a bit of mind-boggling concept, poorly explained, using jargon, sometimes with errors, and expecting those who are new to the concept to make leaps in understanding that are taken for granted by those who are already familiar.

And understanding and covering that gap makes the difference between great teachers and experts on subjects that are poor teachers. I’m sure we all know those teachers.

Another apt analog is poor UX vs. great UX. One makes software horribly confusing and frustrating to use, the other understands and meets the user where they are, and takes them through logically and intuitively.

  **Your browser information:**

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0

Challenge: Replace Loops using Recursion

Link to the challenge:

There does not exist a single description of recursion that works for all learners. We provide a brief description that works for many learners and encourage all learners to use Google and ask lots of questions.

It’s mind boggling because it is hard, not because people aren’t putting in the effort to try to explain it. A lot of work has gone into refining this explanation over many years by this point.

Recursion is simply a hard corcept. It requires good grasp of the fundamentals of functions - scope, return values, calls, etc - and the willingness to try something new and somewhat strange feeling.


I’m seeing that you have a lot complaints about the challenge text, but do you have any specific suggestions to modify the instructions while still keeping them short?

Firstly, thanks for actually reading and replying.

Warning: this is going to be another long comment…

I suspect there’s maybe too much of an emphasis on trying to make the explanation short that is part of the problem. It should only be as concise as is necessary to adequately explain the concept.

I’m also not saying people aren’t putting effort into explaining it, or that it is explained poorly by choice. It’s just a mental phenomenon that experts can sometimes gloss over fundamental ideas and concepts that to them are so basic, so “common sense”, that they take them for granted, but can be critical to a beginner’s understanding.

As the quote (supposedly) attributed to Einstein says, “Everything should be made as simple as possible, but not simpler.”

And I know this certainly applies to programming. :laughing:

I understand your saying that it requires a grasp of various fundamental concepts, but those concepts are simply not referred to in the existing explanation. And sometimes, the problem can be in the structuring of the material even if there weren’t already some critical gaps.

Anyway, onward to the specific suggestions! As someone new to the concept, the explanation should at the very least include upfront:

  1. the idea that the function being “expressed in terms of itself” refers to it calling itself repeatedly (and that holy cow, this is something we can actually do in programming)

  2. that we do this in an attempt to break a larger problem down into smaller parts, step by step (programmatic method)

  3. that it does so by calling function(n) and then function(n-1)… etc, getting “smaller” or “working backwards” so to speak,

  4. that the base case is critical so that the function has a condition to stop calling itself instead of calling itself forever and crashing your browser/computer

  5. and then the idea of and relationship to the call stack and how these function calls are then “layered” on top of each other (so as to understand why and when to use a push or unshift)

  6. and finally, a brief comparison with loops and an idea of why and in what cases recursion would actually be the best solution,

  7. and just for the worst case, how it’s ok to not fully grasp it at this point.

I feel this last point is important because I wouldn’t be surprised if some people decided they couldn’t program because they couldn’t wrap their heads around recursion at this point, especially when this is the “Basic Javascript” module and it seems not to be that commonly used except in particular instances/fields?

I understand that some of these may seem like very explicit “duh” statements, but laying it out like this would have made it infinitely clearer.

Interestingly, in breaking down these points, it doesn’t seem like it would end up making a very long explanation. Maybe it’s hard because we keep saying it’s a hard concept and inadvertently it becomes so because some seemingly obvious (but not obvious to beginners) parts of the process are unintentionally left out.

If it does somehow end up being too long, and the intention is to make the page short, we could always link to one or some of the links as required reading. I made it a point to try to include mostly links from the freeCodeCamp community, so my 1st 3 links to better, clearer explanations are all articles, on the site, by community contributors.

The first one stuck with me particularly, as it was very clear, very systematic, and had very helpful illustrations.

“In its simplest form, a recursive function is one that calls itself.” As explained by Beau Carnes

Sorry if the original post was particularly whiny and “complainy”. There was definitely some frustration behind it. But also, it was also partially a note to self to break down the problem and help myself come to terms with it. And honestly, if this helps at all to make a clearer explanation, we all benefit.

Again, thanks for reading and replying. I really do appreciate the effort that’s gone into the site, making the lessons available for everyone, maintaining and updating, replying to comments, etc. And I hope this ends up being helpful somehow.

because that will be multiplied to the numbers in the array - if we return 0, the output of the multiply function is always 0

same reasoning as here

Thanks for the reply, ilenia.

I still don’t think that’s right though. Or is there something I’m just not getting?

In the first instance you choose a variable product to be 1. Yes, it makes sense because product is not the given n numbers to multiply, but is used to multiply the item in the array.

But in the 2nd instance, if n is <=0 this means the initial request to the function itself is to “multiply the first <(i.e. -1, -2) or 0 items in the given array”. AKA there should be no multiplication happening.

Right? No? What am I missing? I still don’t get why you would return 1 instead of 0 or an error message of some kind.

If I wrote this function and it returned 1 when I asked it to multiply the first -2/-1/0 numbers in the array, I would think it was broken. Is there some logic I’m missing?

n must be >= to 1 to produce any proper result. But if i put in numbers <= 0 as a joke, or to test, it, it should not multiply anything. and I should not get 1?

I’m pretty sure in this case saying multiply the first 0 numbers of an array arr is not the same as arr[0] and the 1 returned is not actually used in anything? Is that wrong?

Please enlighten me.

It’s replicating the same behaviour as here, you are fine here with it returning 1 as default

Try to call this function as multiply([], -3), it gives 1

As the behaviour is the same you can use the same explanation you used before