Welcome to module 2, in which we will complete the construction of our virtual machine. In the previous module, we dealt with what we called arithmetic logical commands and memory segment commands. And notice that what we did provides a very limited view of programming. Everything was kind of pre-determined and we did push, pop, add, subtract and so on. And we assume that the program continues in some steadfast linear fashion. Well, today, we'll begin to discuss the notion of program control, in which the flow of control of the program takes all sorts of twists and turns due to if commands, goto commands, function calling commands and so on. So let's start with an example. Here is a mathematical expression which is well known to anybody who had some high school math. And here is the same expression expressed in some high level language. And notice that the high level expression is almost as good as the real thing. That's why we call it high level language, because it allows programmers to write programs in a style that is very similar to the way we think about these applications, in this case, mathematical expressions. Now, this expression that I have here, b square- 4ac, is widely used in some branches of mathematics. So perhaps I can generalize what I have here and use a new function, I called it disc for discriminant because that's the name of this expression in mathematics. And if I have to compute this expression many times in my program, it may make sense to refactor it into a method, give this method or function a name. We called it square root and use it whenever the need arises. So let's kind of step back and see what we're doing in sort of a greater perspective of programming theory. Well, sqrt, power and disc are abstractions, they are not part of the basic language. The basic language, whether it's Java or Python or whatever, has a limited syntax and a limited repertoire of commands. But here I'm allowed to invent so-called new commands as I please, which is wonderful, right. Whenever I need a new function, I just make it up as I just did with this function that I called disc. And I should ask myself, what about the implementation of these functions? I mean, it's very nice to write disc and put parentheses and assume that someone will deliver this computation, but who will, at the end of the line, realize this function? Well, the beauty of this practice is that it doesn't really matter. I can invent new abstractions at will and assume that at some point, someone will implement them. This someone will either be myself on another day, or later on today, or next week, or someone else will do it for me. If I'm a team leader in some software development company, I can assign one of my team members to do it for me and so on and so forth. The beauty of this is that the story of implementing these functions is completely separate from the story of using them. And I can begin using them before they even implemented because they can assume that they will provide some value. And I don't care which value. I can continue to write my program. And even debug it using some dummy values and so on. So this is a very elegant practice, and the bottom line is this observation that the basic language can be extended at will. In fact, the basic language is very limited. It has only so many commands. But these extensions are infinite. I can make the language as sophisticated as I please, and this idea of giving the programmer the freedom to add more functionality to the language is, perhaps, I'm afraid to say it, but it may be the greatest idea in high level languages. In fact, in programming in general, the idea that you can extend a language as you please. Another aspect of program control, in addition to functions, is the notion of branching. And using this example of computing the so called discriminant, because of some mathematical reasons, it makes sense to first check if a is not equal 0, and only then compute this computation, otherwise do something else. The logic here is not really important. And if I write this and I give it to a compiler, well, the compiler will generate this pseudo VM code. How the compiler achieves this magic is something that will be dealt with in modules four and five, I think, of the course, so you don't have to worry about it right now. You don't have to understand how this transformation took place. But if you look at the code that was generated, you will realize that we have a whole set of new commands that we haven't seen before. And these commands boil down to branching commands, which are goto, if-goto and label, three branching commands. And function commands, which boil down to call, function and return. So this, in a nutshell, is what we're going to do in this module. We're going to discuss these commands, and we're going to discuss them from two different perspectives. One of them will be understanding the abstraction. That is, we have to understand how to do branching and function, call, and return within the VM language. This is something which probably is completely new to most of you, because we know how to do branching and function, call, and return in a language like Java or Python. But when we go down to the level of the virtual machine, there are other rules of how to do it, so we'll have to learn how to do it. Then we will also have to learn how to actually implement these functions. How to make them actually work and deliver their effect. So two very different things, right, abstraction and implementation. So in the course of learning all these new things, we will go through some very important take home lessons. First of all, we will learn once again the abstraction and implementation of branching and function commands and it will understand how they actually work. We will spend a lot of time going through the function, call, and return dance, if you will, which is a very intricate and fascinating process that happens behind the scenes. And in the process of running this dance, the computer also has to sort of allocate memory to the main actors of this dance, which are the functions of calling and returning from each other. So we have to understand how memory is allocated dynamically to executing functions and we'll continue to talk about stack processing in actually even a much more detailed fashion than we did so far. And obviously we'll have to deal with pointers. And we'll have to complete the VM implementation, which is a very interesting programming assignment. So altogether, we're here for a treat in which you will completely understand how functions call each other, and return safely from these ventures and you will also have a very rewarding programming assignment. So moving along, let's go to the next unit in which we discuss branching.