 Hello and welcome back. In this lecture we are going to look at the use of functions in programs. Here is a quick recap of some relevant topics that we have already studied. We have looked at various constructs that allow us to write some useful programs. Specifically we have looked at assignment statements, input output statements, expressions, sequential and conditional statements and also looping constructs. However, so far all of these constructs were encapsulated within the same main function. In this lecture we are going to break away from the monopoly of main. We will have other subunits of a program that can also do computation and we will see that it indeed reduces the burden of programming everything that we wanted to compute inside one single main function. Specifically we are going to look at functions other than main. We are going to look at how these are used in programs and in this lecture will keep our discussion simple. We will simply look at a contract centric view of programming with functions. Now, to get going let us pick up a simple example through which we can illustrate the use of functions. So, in this example we want to store the quiz 1 and quiz 2 marks of all CS11 students in an encoded form. Why might we want to store it in an encoded form? So, that others cannot figure out the actual marks even if they get access to the encoded form. So, what should be the encoding strategy? Let us say that we are going to choose a simple encoding strategy. So, an ordered pair of marks m comma n, m is the marks in quiz 1 of a student, n is the marks in quiz 2 of the same student. We are going to encode this ordered pair as the single integer 2 raise to m times 3 raise to n. And let us assume that all marks are integers in the range 1 through 10. Now, for those who know about how any natural number can be factorized uniquely as the product of powers of primes will realize that since 2 and 3 are prime numbers. If I give you this number 2 raise to m times 3 raise to n as 1 integer, it is not difficult to extract out m and n from the single number. And therefore, this is indeed an encoding that can be decoded without any loss of information. Nevertheless, this is the encoding strategy specified and we have got to write a C++ program that does this. So, let us look at how a C++ program for this problem might look like. Here is the main function, within it we have several integer variables declared. Then we ask for the number of students, read in the number of students in this variable num students and then we iterate in a for loop for every student. So, we iterate num students number of times and for each student we ask for the quiz 1 and quiz 2 marks, read those in and then we compute the cipher, the encoded form from quiz 1 marks and quiz 2 marks and within store the count and the cipher in an appropriate file. Now, since we have not studied how to do file operations, I am not going to elaborate on this comment further now, we will however elaborate on this comment. Now, how do we compute the encoded from quiz 1 marks and quiz 2 marks? We have seen that this has to be 2 raised to quiz 1 marks times 3 raised to quiz 2 marks. How do I compute 2 raised to quiz 1? Here is a simple for loop which will help us do that. Notice that in this for loop I have the simple counter i which starts from 0, the loop condition is i less than quiz 1 marks and the loop counter is incremented every time I go through the loop. So, this loop is going to be iterated exactly q 1 marks number of times and in each iteration I am going to multiply 2 raised to q 1 by 2, where 2 raised to q 1 is originally initialized to 1. So, in fact, the entire job within this loop is done within this part of the loop, the 3 different parts of the for loop, the actual body of the for loop is completely empty. By a similar logic, this loop calculates 3 raised to q 2 and then we multiply them together to get the cipher. So, we could put that code in our C++ program fragment, but now you know we have code here for reading quiz 1 marks, quiz 2 marks, outputting some statement. We have code here which is computing 2 raised to q 1, 3 raised to q 2, multiplying them up to compute the cipher. So, we have basically mixed up longish code fragments with different purpose. Of course, in this case the code fragments are not very long, but in a more realistic scenario, each of these code fragments doing I O or doing some cipher calculation could be much longer. Now, when you mix code fragments with different purpose, it hurts the readability or understandability of the code. So, we would like to avoid this. Well, there is also another problem here. If you look at these two for loops, they are basically repeated code with very small changes and this is really, really bad. This is in fact a recipe for introducing errors in some copy of the code. So, we would not like to have this repeated. So, can we encapsulate this task that we have here for computing a cipher as another computational sub-task which would take quiz 1 marks and quiz 2 marks as input, compute the cipher and return it back to us. Well, it turns out that in C++ we can do this. We can do it in the following way. We could say my encode as a function which is fed q 1 marks and q 2 marks as inputs. It returns a value which I can then store in the variable called cipher. So, note here my encode is the name of the computational sub-task. I have just formed such computational sub-tasks are also called functions and if you recall our earlier lecture on naming conventions, the same naming conventions as for variables apply also to names of functions. When we call such a function to do a computational sub-task, we say that we have invoked or called the appropriate function in this case my encode. Q1 marks, Q2 marks are inputs to this function just like we provide inputs to the main function to compute some result and every function evaluates to a value and has a type. We had already seen this earlier in our lecture on naming conventions and type declarations. In this case, my encode evaluates to a value of type int which can then be assigned to this variable called cipher. Well, so I could now use this statement in my program where I am invoking my encode, but I need to specify somewhere in my program file that my encode is a function that it takes integer inputs and that it computes integer values. Why is it necessary to specify this explicitly? Because this is going to be used by the compiler to enforce that my encode is always used in the correct way. We do not want to provide a string as an input to my encode and it is also used by the compiler to allocate space for the return value of my encode and also space on what is called the activation frame which we will see in a later lecture. So, why does all of the specification of my encode come in? It comes in just like we declare variables. We have to declare that my encode is a function whose return value is of type int. It takes two arguments. We will call them q1 marks and q2 marks and both of them are of type int. Well, having done that, we must still specify what the instructions my encode should execute in order to compute cipher from its two ordered inputs. So, we need another piece of code where I must specify how cipher is going to be computed from its two ordered inputs and we know what this code looks like. We have already seen this earlier. The interesting point is that in this code I am using variables like i 2 raise to q1, q1 marks and so on. Now, are these variables the same variables as they were in the main function? The answer is no unless we explicitly require two different functions to share variables in general each function will have its own copy of variables. So, in this case we can declare these variables once again inside the function my encode and these will be local variables of my encode. They will never be mixed up with the variables declared in main unless we explicitly ask for sharing between sharing of variables between functions. In fact, we passed values to my encode through these two variables q1 marks and q2 marks of type int these are also called formal parameters of the function and these will also be viewed as local variables of my encode. So, as you can see there is really no confusion between the variables used inside a function and the variables used inside main and in fact this will be true for any two different functions. Well, so my encode compute cipher but then we wanted this value to be passed or returned back to main. How do we do that? We do that by the special statement called return cipher. So, now you see that this return statement is really needed to say that go back to the calling function and give it the value cipher that I have computed over here. Well, of course, the value of this the type of the return value must match the declared types of what this function evaluate to in this case it is an integer. Now that we have seen a simple usage of functions, let us try to understand how we might also want to view functions when we are calling them from a function like main. So, in fact, when I call the function my encode from main I really need not worry about how inside my encode the cipher will actually be calculated. I can think of the internals of my encode as a complete black box. In fact, what I need to know when I am calling my encode is what are the preconditions, what does my encode expect its input arguments to satisfy. So, here the preconditions might be like this that both the input arguments lie between 1 and 10 and what are the post conditions, what are the relations between the returned value and the input arguments that my encode is going to guarantee if I satisfied the precondition. So, in this case the post condition could be returned value is 2 raise to q1 marks times 3 raise to q2 marks and no other side effects. We will see in a later lecture what side effects of functions mean. So, once I know the precondition and the post condition of my encode I really need not care how my encode actually computes the cipher. When I am calling my encode inside main all I need to ensure is that the precondition of my encode is satisfied before I invoke my encode because that is what my encode assumes about its inputs and once I have satisfied the precondition my encode is going to guarantee the post condition. So, after this function is invoked and this assignment happens I am guaranteed that the post condition of my encode is satisfied. Now, we have seen the use of a function within main could we have one function within another function well let us look at the function my encode that we just wrote. In this function we have precondition post condition and the code that we have already seen earlier. However, once again we have these two statements for loops which are almost repeated and so the question here is can we avoid this repetition and in fact an interesting question to ask is can we use another function within the function my encode and perhaps this function could just compute the power of a base raise to an exponent. Well if I did that then my implementation of my encode would look something like this I would say 2 raise to q 1 is 2 raise to q 1 marks 3 raise to q 2 is 3 raise to q 2 marks the exponentiation here is happening through this power function and then of course I need to write what this power function looks like. So, this power function must take a base and an exponent it is going to assume as a precondition that the base is greater than 0 the exponent is greater than equal to 0 and it is going to use that simple loop that we have already seen earlier compute the result and return the result. So, the post condition that it guarantees is that the result is base raise to exponent and once again there are no side effects. So, here is how the overall program structure might look like I have declared two functions that I want to use I have declared what kind of arguments it takes what kind of values it returns here is my main function which calls the function my encode provides two arguments to it the function my encode has its own preconditions post conditions and it in turn invokes the function power and provides arguments to it the function power has its own preconditions post conditions and it raises the base to the exponent and returns that value. So, in summary we saw simple use of functions in programming and we have seen that by using functions we can do modular programming we can do separation of concerns we can solve a small sub problem in a function and then use that solution in a larger sub task and we have also seen the contract view of functions where we specify preconditions post conditions and that is all that we need to know when we invoke a function. Thank you.