Welcome to Unit 1.1 in our Virtual Machine module. Here again is the big picture. And we already know how to deal with the hardware. We know how to write programs in the Hack semi-language. And we are ready to move on. And, actually, we are now beginning the process of writing a compiler for a modern object based language. And because this is quite a substantial task, we'll divide it into quite a few modules. Beginning with this one, module one. And because in this course we do everything bottom up. We'll start on the right-hand side of this roadmap here, and we'll begin writing our VM translator. But before we actually get into all these nitty gritty details of building the virtual machine, I think that it makes sense to actually take a look or have a sneak preview at the end of our journey, and talk about the overall task of compiling a high level language. So let us once again review the code that we saw before in the previous unit, in which we manipulate some points in a two-dimensional space. And I wish to remind you that if you run this code on a computer, then you'll end up seeing some output flickering on the screen. Now, this is not just a bunch of characters. These are point that were derived using vector algebra and the Pythagorean theorem and so on and so forth. So indeed, it's kind of staggering how we accomplish that, how we started with this abstract program on the left and then ended up with something that actually runs on the computer. How can we make it happen? Well, first of all you need the computer. So if you took Nand to Tetris part one, you build such a computer. But even of you had such a computer, you would still need to translate all the way from high level to the machine language of that computer. And that's what Nand to Tetris part 2 is all about. So how do we do it? Well you know the answer, we need a compiler. We need to translate from Jack, in this case, to the hack machine language, or to any other machine language that comes to your mind, so we need to write this compiler. So, already now, we have a major problem, and the problem is that the world consists of many different computers. So, if you start with some high level program, you would like your program to run on many different platforms. On laptops, desktops, tablets, smartphones, digital watches, and so on. And the problem is, that many of these devices use different processes. And these different process have different machine languages. So it's not enough to write one compiler only, you have to develop many compilers, one for every different processor. And if you are practicing software developers, you have to translate your program to many different target platforms. You have to maintain multiple versions of your code, which is a major pain. So I'm pleased to tell you that there is an alternative. And the battle cry of this alternative is, write once, run anywhere. As opposed to, write once, and fix everywhere. And the best example of this approach is, probably, Java. Now Java does not compile all the way down to machine language. Instead, Java employs something called two-tier compilation. So in the first tier, we can call it the top tier, the Java compiler translates the Java program into something called in the world of Java, it's called bytecode. But in general we call it VM code. Now this VM code is designed to run on an abstract artifact called a virtual machine. It's not a real computer, it's an imaginary computer. So, if we want to actually execute this bytecode, we have to translate it further into machine language. We have to realize it on some real von Neumann machine or some real hardware device. So, in order to do this we need the tier two, the second tier or the bottom tier of the compilation process in which we equip the target device with something called JVM implementation in the world of Java. The Java machine implementation. And the JVM implementation is a program that takes bytecode and translates it finally into the target code of the target platform. And we need such a translator for every platform on which we want to execute our VM program. And you see the translation gap between the high level and the low level is huge. And by introducing an intermediate level, we are decoupling this very complex process into two separate standalone sub-processes. The compiler and the VM translator or the VM implementation. And everyone of these translators is significantly simpler than the compiler that we saw before, that goes all away from from top to bottom, for example like C++. So we have broken a very complex task into two simpler tasks which is always desirable. And in fact, Java should not take credit for this idea of two-tier compilation because the idea is about, and the practice is about 30 years old. And in fact, if you think about it, it's almost believe it or not, it's almost 90 years old as I will comment later on toward the end of this module. So how do we do it in Jack? Well, Jack is a Java-like language which we use in this course. And we are going to execute Jack programs on two different platforms. One platform will be your own PC, whatever PC you're using. And the other platform is going to be the Hack hardware that we built in part one of Nand to Tetris. If you didn't take Nand to Tetris part one, don't worry about it. You don't need the actual Hack computer because the Nand to Tetris software suite, which is now sitting on your computer, includes an emulator that simulates the Hack computer on your PC. So it can do everything that has to be done in this course using this simulator. So, how do we bridge the gap between Jack and these two target platforms? Well, we do something very similar to what we did with Java. We will write a compiler that compiles Jack programs into what we call VM code. And then we'll equip your PC with something called VM emulator, which is a piece of software that knows how to take a VM program and actually execute it on your own laptop, or whatever machine you're using. At the same time and parallel to this approach, we will also write a substantial program, a VM translator that takes the VM code and translates it into the machine language of the Hack platform. And this actually will be sort of the pinnacle of module one, of what we do in this particular module. But it will take us several units to get to this level, several units of instruction. So to sum up, in this module and the next one, we are going to write the VM translator, we are going to first of all understand what is a virtual machine and then we are going to implement it. And then in modules four and five we are going to write the compiler that will complete the overall compilation picture. Now, I wish to remind you that the virtual machine is an abstraction. It's an imaginary artifact. And it's an example of what we call virtualization. Which is one of the most important ideas in the theory and practice of computer science. And you cannot do cloud computing, and communication networks, and modern programming languages, without using this notion of virtualization in a major way. Now, I can think about one person who will be delighted to see what we're doing here and this is Alan Turing. One of the most distinguished grandaddy's, if not the most distinguished grandfather of the computer science field. Almost 90 years ago Turing wrote a seminal paper in which he described an abstract computer. That had the ability to basically execute computer programs abstractly. And he also described something he called Universal Machine, now it's called Universal Turing Machine, that can take any other machine and emulate it's operations. And by doing this, you know, by thinking about a machine that executes another machine or a program that executes and understands another program. A program that creates another program is data. By doing this Turing really put computer science on a completely new level of sophistication. Because, you see, this notion of thinking about thinking. This is a hallmark of intelligence, in general. What's the difference between you and your dog? Both of you are thinking creatures. But you can think about thinking. And I'm not sure that your dog can perform this trick. So, in computer science, we can write programs that analyze other programs, that run other programs, manage them in all sorts of different ways. And this ability to sort of reason about reasoning is what makes computer science such a sophisticated and powerful field. Now, we don't have too much time to talk about it, because this is a different course. And with that in mind, I'm reminded of some very nice quote that Turing said, and that is, we can only see a short distance ahead but we can see plenty here that needs to be done. And I think this is a very good slogan for this course, and with that I want to remind you that this is our overall map. We have plenty of work to do, so enough talking about thinking about thinking, and let's build some computers. So in this module we are going to focus on the virtual machine, and we are going to do it using two separate perspectives. First, we'll think about what the machine can do for us, this is the abstract view of the machine. And then we talk about how to actually build it, how to implement it and make it work. This module is going to introduce lots of goodies. First of all, we're going to talk about compilation as we have done already. We are going to understand virtualization in a very intuitive and deep way. We'll talk a lot about VM abstraction. By doing this you will understand how the JVM or Java works and how the virtual machine of C# works, and so on. We will learn how to use stacks, which is a very important data structure in the theory and practice of computer science. We will actually build the virtual machine, we will implement it. And in doing so, we'll use pointers, and we'll also do a good share of programming. So a lot of fun is coming up, bear with me, and let's move on to the next unit.