 Hello and welcome back. This is the first part of a two part lecture on recursive functions. Here is a quick recap of some relevant topics that we have already studied. We have seen the use of simple functions in programs. We have seen the contract centric view of programming with functions. We have seen how control flows in a program with function call and return. We have seen the usage of activation records and call stack to implement this flow of control. And we have also seen the two paradigms of parameter passing call by value and call by reference. However, so far whenever we called a function, the caller and the cally functions were different. They were not the same. In this lecture, we are going to let the caller and the cally be the same. This is what gives us recursive functions. So, in this lecture, we are going to look at how recursive functions work and how activation records and the call stack is managed when we have recursive functions being executed in a program. So, let us recall the encoding example that we had seen a few lectures back. We want to store quiz 1 and quiz 2 marks of all CS 101 students in an encoded form. We had agreed to encode a pair of quiz marks in the following way. If m and n are quiz 1 and quiz 2 marks, then their encoded version would be 2 raise to m times 3 raise to n. We are also assumed that all marks were integers in the range 1 through 10. Here is the structure of a simple C++ program that we have looked at earlier for solving the same problem. In this C++ program of which I have just shown the skeleton here, only highlighting the parts where function calls are made. In this program, there are two functions, my encode and power. Inside the main function, we have a for loop which iterates over all the students in the class, reads their marks and then invokes the function my encode to compute the encoded form of quiz 1 marks and quiz 2 marks. The function my encode in turn calls the function power which basically computes 2 raise to quiz 1 marks and 3 raise to quiz 2 marks and using that my encode computes the encoded form and returns it to the main function. Now, if you look at the structure of this program, you will notice that the my encode function is being called from within the main function, but these are two different functions. Similarly, the power function is being called from within my encode, but once again power and my encode are two different functions. Now, one can ask that well instead of letting one function call a different function, what would happen if we let a function call itself or what would happen if we let two functions mutually call each other. So, function 1 could call function 2 and function 2 in turn could call function 1. What could possibly go wrong if we let this happen? Well in order to understand how this might work or not work, let us try to look at the specific example that we have just seen which is the encoding example for CS 101 students and observe that this encoding function instead of being written as 2 raise to m times 3 raise to n could also have been written in the following way where I am saying that given m and n where both are greater than 1, the encoded version of m and n is obtained from the encoded version of m comma n minus 1 and because I have reduced n by 1 and 3 appears in the exponent, therefore I have to multiply this encoding by 3. Similarly, if n is equal to 1, but m is greater than 1, then I could compute the encoded version of m comma n as encoded version of m minus 1 comma 1, n is already 1 here multiplied by 2 and once again why is this multiplication by 2, because I have reduced m by 1 and m appears as the exponent of 2, so I have to multiply this encoded value by 2. And finally, if m and n both become equal to 1, then the value of the encoded function is 2 times 3 which is 6. So, what I want to draw your attention to in this slide is that when I just specified the problem like this, we came up with a C++ program which solved this problem, but now instead of specifying encode m n in this manner, I am basically writing the same function, but in this alternative manner where I am saying to compute the value of encode m comma n, if I already had the value of encode m comma n minus 1, then I could multiply that by 3 to compute the value of encode m comma n and similarly for encode m minus 1 comma 1. Now, once you agree that encode m comma n can be written like this, it naturally lends itself to an alternate encoding program. In this program, we are going to use a new encoding function. I have called it newEnc. This also takes two integer quiz marks and returns the encoded version of these two quiz marks. However, function newEnc operates very differently from the previous function which was myEncode. The precondition and post condition of newEnc could be the same as what it was earlier, which is that both quiz 1 marks and quiz 2 marks should be between 1 and 10 before we call this function. And at the end of this function, the return value would be 2 raise to quiz 1 marks times 3 raise to quiz 2 marks. However, the internals of newEnc is going to be very different from what we had seen earlier. Specifically, we are going to use this form of specifying the function encode m n. So, we are going to say that if quiz 2 marks is 1 and then if quiz 1 marks is also 1, return 6. However, if quiz 2 marks is 1, but quiz 1 marks is not 1, but something greater than 1, then I am going to call newEnc again by reducing quiz 1 marks by 1, passing the second argument as 1 because quiz 2 marks is already 1. And I am going to multiply the result by 2 and return that. If you notice, this is exactly what we were doing over here. And then of course, I could have code implementing the other part of this formulation. I have not shown that here for the sake of clarity. But now what you see is that while here newEnc is being called from within main, over here the same newEnc is being called from within itself. And this is different from all that we have seen so far. So, we might ask that how do activation records and the call stack operate when we have a function calling itself. Well, let us see how it might operate. So, here we have a caller function which is newEnc and the call function is also newEnc. We are calling newEnc from within itself. Let us suppose that we are currently executing this function newEnc. So, in our call stack we already have the activation record for main. The operating system had called main. We also have the activation record for newEnc main had called newEnc. And now we are within this execution of newEnc. And now we encounter this call of the function newEnc. Whenever we encounter a function call a fresh activation record for the callee must be created. So, the callee here is newEnc. The values of function parameters from the caller which is again newEnc will be copied from the activation record of the caller to the activation record of the callee. The callee also happens to be newEnc although these two activation records are distinct. The PC of the caller which is newEnc is saved and other bookkeeping information is updated. And finally, the activation record of the callee is pushed on to the call stack. So far good. So, let us see what happens when a function returns. So, here the callee is newEnc and let us say that it is going to return now. So, this was our call stack and the top most activation record in the call stack corresponds to the invocation of newEnc which is now going to return. So, we know what must happen. The callee's activation record must be popped from the call stack. The return value computed by this execution of newEnc will be copied from the activation record of the callee to the activation record of the caller. The caller also happens to be newEnc in this case. However, these two activation records as we have said earlier are very different. The value of the PC saved in the popped activation record will now be loaded in the program counter of the CPU. This program counter basically tells you where in the caller function which happens to be another invocation of newEnc should be returned to when the callee function which happens to be the next invocation of newEnc returns. Then the activation record of the callee is freed up and finally, we resume execution at the instruction given by the location where the updated program counter points to. So, what we find is that even if a function was allowed to call itself, there does not seem to be any problem. Same mechanism of function calls and returns that we have studied earlier seems to work perfectly well. And this is good because this means that we can now allow functions to call themselves and such functions that call themselves are also called recursive functions and we will see shortly that they often provide an elegant and natural way to solve several problems. We could also have mutually recursive functions. In this case, a function does not call itself directly, but one function calls another one which in turn may call a third one and the third one in turn may call the first one back. So, basically we have a cyclic chain of functions calling each other such that the cycle is completed. Eventually, each function gets called from itself through the cycle. But even in this case, our mechanism of using activation records, pushing and popping them onto the call stack seems to work perfectly well and there is really no problem. So, we could also have mutually recursive functions in our programs. So, since this is fine, we know that everything is going to work fine. So, therefore, now we can have this alternative recursive solution for our encoding problem where I have highlighted the recursive call of new and from within itself. Of course, there is an incomplete description of the new and function that are going to be further recursive calls in the part that I have skipped over here. So, in summary, we have looked at recursion as a programming construct. We have also seen how activation records and the call stack operates in exactly the same way that we had seen earlier as in the case of recursive calls. Thank you.