 All right, a little bit about me. So February 14, 1983, over a Valentine's Day, yes. Over the weekend, I did a lot of work with computers. I'm working on a simple machine language game for the Apple II. Machine language is the only language a computer understands, and it's consisted of binary number codes. Probably needed a technical editor or copy editor there. All other languages are converted to this language. And I'm going to make a game that's going to be, oh, and I'm going to make a game that's going to be trying to move a man through a field of moving dots. Very exciting, very exciting. There's a picture of me and my cat about from that area. And let's write some code. I have always been kind of fascinated with the workings of machines, like computers and kind of low level details and so forth. And if you start working with machines, you start coming across different kinds of structures and so forth. And one of the things that you might come across is just like a stack. Stack is actually really easy to implement in Python. You can do it with a list. So maybe we make a list and then a stack has like two operations on it. You have like a push item where you can just append something onto your stack there. And you have a pop where you just return something coming back. Now stacks are actually kind of an amazing thing. I'm not going to do a demo of that. But you have a stack. It turns out that stacks can be just used for all sorts of amazing stuff, like actually making like little machines. Like you can actually make like your own like little machine code or your own little executor or something like that. And so an example of what something like that might look like is you can basically come up with like your own like little machine language. This is an example of kind of a stack-based machine language that computes 2 plus 3 times 0.01. And here's how you might do something like that. You can take like your stack, give it an execute function or a method like that. Maybe I'm going to change this into the name machine at this point. And what you will do is just write a little like a little loop where you just execute op codes in this like instruction sequence. Like you can say, give me an operation and then maybe some arguments to the instruction. And then you can write a little like a little machine. Like you can say, if op is const, then maybe you push something onto the stack. If op is add, for instance, maybe you pull things off the stack. Like you get the right thing off the stack. You get the left thing off the stack. And then maybe you put the result back onto the stack. So self-push of left plus right. You can do the same thing for like a multiply instruction, for instance. OK, so you can take that code, do multiply. And all of a sudden, you're kind of on the way to making like a little machine here. I'm going to put a print statement in here just so you can see what's happening. So maybe print the op, the args, what the stack is. I'm also going to put a little safeguard in here. Just in case I screw up, I'll get an exception message sort of saying like a bad operation. OK, so you might start with something like that. And I used to think this was amazing when I learned about this as a, I don't know where I learned about stack machines. It probably was not middle school. But somewhere along the way, I learned about stacks and the fact you could make machines. I just thought this was like totally cool. So the way that this works is you'd make like a little machine and then you'd execute code. And then if it worked, like the result would just be there on the top of the stack. So let's give that a try and actually see if it works here. So you would just say Python, you know, Python 3 machine dot pi. And nothing happens. Let me, let me see what happens here. I got execute code. Oh, I need a main function. OK, so your job in the front row, by the way, is to do kind of a code review. Like I don't actually use syntax like tooltips or anything like that. So I need more like an audible version, like kind of the louder and like more yelling that takes place. I'll know that, I'll know that something is wrong. OK, so, self.stack, self.push, oh, items, items. OK, no, OK. Nothing like live debugging to, OK, OK, so, OK. So get this, get this, get this stack we're going here. What you see is it's sort of churning through operations and it comes up and prints result 2.3. OK, awesome. You know, it's like I've got the start of like a little, like a little machine here. And if you start playing around with these machines, you start thinking, maybe I could make this more like a, more like a CPU or something. I could give it more features. So maybe one of the features that you might want to give it is some memory. I don't know, maybe we're going to make like a byte array of some, of simulated memory of some kind. The most memory that I'll probably ever need is 64k. So I'll give it like kind of a default size like that. And then maybe I'll start building like some functions to kind of load and store from memory. Again, I'm thinking like, can I make like a little CPU or something like that? Now the problem with loading and storing is that I'm going to have to make some decisions about how this memory actually works, right? I mean, OK, I'm going to have to pull something out of the memory and I have to make some like decisions of what's here. So for lack of a better, I guess a better alternative, I'm just going to assume that everything is a floating point number. Maybe I've been doing too much JavaScript or something like that, OK? So we're going to, we're basically going to do like some memory unpacking here of value. If you haven't used the struct module in Python than before, that's a way of kind of packing values. OK, so we're going to have this machine. It has like a load and a store and a pack and unpack kind of thing. In order to use that, I've got an import struct. And then I'm going to give that sort of more, I'm going to give myself sort of more instructions here. OK, so if there's like a load instruction, what I would do is get the address by kind of popping that off the stack and then pushing on like the value of loading it. If I wanted to do a store, I would get a value off the stack and then I would get an address off the stack and then I would put that into my memory. OK, so store it address value. So if you add these kinds of instructions, suddenly your programs become a little bit more powerful. You can start having the concept of variables maybe, like X is 2 and V is 3. And maybe I do computations like X is equal to X plus V times 0.01 or something, where I'm now like reading and writing data on my machine. In order to make that work, what you have to do is basically give like these things a memory address. I'm actually introducing like the concept of a pointer here. So I have to pick some number, like some address for this X is going to live. I don't know, does anybody have a favorite number? 22, OK, that can work, OK. X is going to be at 22, V will be at, I don't know, 42. OK, fair enough. So what will happen now if you wanted to load from variables is you kind of have to, you have to put like the address of a variable on the stack and then you would load it and then you would put the address of the other variable on the stack and you would load that. And then at the end, what you would have to do is store the value. Now the store is a little weird. It turns out the way I have this structured is I have to put the address first and then you put it through the value afterwards. So you kind of put these like addresses on there, loads and stores. And then the way that the machine would work is you'd have to set up some variables. So like I'd basically say, well, at X address, I'm going to store two. And at the V address, I would store three and then I would execute my code. And then at the end, instead of popping something out, I would just load it out of it. Okay, so kind of building up the machine, giving it kind of memory here. You have memory addresses, load in store and I'll keep my fingers that this thing still runs here. Self-store value. Okay. My cat is cute, but I don't want to keep looking at that. I just have a typo in the variable name. Front row, you're letting me down on a typo there. Okay, so if we do that and it comes back with kind of the same result, we're doing load and store kind of stuff. Now, somebody's going to look at this code and they're going to say, you know, that's great. I mean, okay, you have math operations and you have load and store and stuff, but you really should probably have like some functions in here or something, like could you have like a function update position that just computes like that result, X plus, you know, return X plus V times DT or something. And then use that, you know, because so I kind of build function calls into my machine. And it turns out that that's not too bad to do as well. What you can do for functions is maybe introduce the concept of a function. There are a few things that are kind of related to functions, like how many parameters do they take? You know, does it return a value? What code is associated with it? So I'm going to add these in here. Typo, okay, I'll come back to that. Yeah, just have to make sure that there. Okay, so you're going to have a few features like that. And then what I'm going to need to do is add a little bit of stuff to my machine to kind of make function calls work. One of the ways that I could do that is I could add maybe a call method where you give me a function and some arguments. And then I set up kind of like a function call. Now, one of the things that you're going to need with functions are a notion of local variables. And like when you call a function, you get like new local variables and parameters and stuff. So I'm going to make like a bunch of local variables. That isn't kind of a neat little trick there. What I'm doing is making a mapping between the numbers and the arguments. There'll be a quiz on this later on. Okay, a little trick with the enumerate function. And then what I'm going to do is kind of pump this whole thing off to the execute function where I'll have some, I'll pass it the locals. And then if the function returns something, I'll pop something off the stack. Okay, so I'm sort of setting up this like little function call where it's like, I'm going to set up some locals, I'm going to go execute the code, you know, pop it off the stack. I'm going to modify my execute code here to take in the locals. And I'm going to build some more features around it. One of the things I'll build are some operations for dealing with the local variables. Like maybe I have an instruction called local get. And the way that that works is it will put something onto the stack by kind of looking it up in the locals dictionary. And then maybe I have another operation local set that does the opposite of that. Okay, so this is kind of like load in store, but it's kind of manipulating that, that like locals thing a little bit. And then the other thing that you're going to need to do function is I need to have some way to call a function. Now this is a little, this is a little tricky with the call. And one of the things with the call is I need to have some way to like reference the function. Like somehow like I need to get like, what am I referring to? Like what is the function object? In order to do that, I'm going to extend my machine with like a little function table. So I'm actually going to pass in functions as like a little, it's an argument here. Okay, so we're going to have like the, think this is like the function table here. Okay, that's coming in. And I'm going to have a, the call operation is essentially just going to look up what the function is. So we'll look up the function, okay, look it up. And then we have to pull some args off the stack. So what we'll do is we'll pop the arguments off the stack here. That underscore by the way is just, I'm disregarding the variable. I'm just like, eh, I don't care about that. One little tricky thing with this popping off the stack is they're going to be in reverse order. So I'm going to flip the, like I'm going to reverse it. And then I'm going to basically call myself. I would say self call, funct with the, with the arguments. And if it returns something, I'll take the result and put it back on the stack. Okay, so you got like, you have function call. What that's going to look like in the little machine code that I'm working on is that you would have to define functions in the machine code. Like I would have to say update function as function, number parameters equals three, returns equals true. The returns by the way, I'm just treating that as a Boolean, like does it return something or not? Okay, so returns true. And then you would give it code that does the function. And so what the code might look like for this is I would say local get zero, that's basically getting the X. And then I would do local get one, that's the V, local get two, that's the DT. And then I would do my math calculations, like multiply it together and then add the results. And then maybe that's just the end of my function there. And here's my function table. Okay, update position. Okay, so I'm gonna have my little function table like that. And what I will do is kind of modify my machine. I'll say, okay, well here's your set of functions, I'll pass in the function table. And then if I wanted to call a function, instead of doing this stuff at the end here, I would replace that with a function call. I would just say call zero. That's the, what was that? Update position or something, whatever I called that. Okay, so you've kind of added, you've added things to your code there. If this is working, I'm not sure it will be, but we'll see. It should produce the same answer as it did before. Oh, man, once the execute takes locals, you gotta pass that third argument in there. Okay, let's try it. Okay, so we get the same answer as before. One little digression, by the way, in one of the breaks, so I've talked to a lot of people at the conference, and I don't remember who it was, but somebody asked me, how does Python work? Like how does Python take like Python code and turn it into like machine instructions or something like that? It actually does this. This might be more than you ever wanted to know, but like if you write up like a Python function, like update position. Okay, this is just pure Python code. xvdt, and you said return x plus v times vdt, like that. What happens underneath the hood of that is Python turns it into like a little Python machine code. It's like, so you see like load x, load v, load dt. You can see like the numbers there. Load zero, load one, load two. This is like exactly the same thing that I did and then there's like binary multiply, binary add, and so forth, this is how Python works. It's actually a little like stack machine, kind of what I'm doing. Now, I'm not actually trying to re-implement Python, but if you're kind of wondering what Python is doing, it's doing that. It's interpreted, okay? So it runs on a little machine there. All right, now continuing in this machine model for a bit, okay, it's like, okay, again, it's like I'm geeked out about like low level details and it's like I wanna know like how do CPUs work and how do machines work. One thing that my machine is missing, well, it's missing kind of a critical feature. You know, not to put anybody on the spot, any thoughts on what it's probably missing here. Okay, well, the one thing that it's missing is I don't have any way to do control flow. Like I don't have any way to do if statements, like if test, you know, consequence, you know, else alternative, things like that. I also don't have any way to do like loops, like while loops or anything. Like this thing is just going through instructions and it just like that's it. And in order to do that, you have to introduce some kind of like branching instruction or something. Like maybe you have a branch instruction of some sort and then maybe you have a conditional branch. So all processors have this, you know, they have some way of branching. But in order to do this branch, you have to do some kind of go-to statement. I mean, you have to introduce like some kind of jump or go-to and like go-tos have a way of sort of offending people. Not to mention that they don't even have them in Python, but so one question that comes up is just what, well, what do you, what's the next best thing to a go-to? Like if you don't have go-to, what would be the next best thing that you could do? And I would claim the next best thing is to simply raise an exception. This is really gonna offend people. They're like, raise an exception. Like what, so what is happening? So if you want the program to stop or branch, one way to do that is just to stop. You're gonna look at that saying like, what is that about? Okay, the conditional branch here is, it's going to be, look something like that. Like if the top thing on the stack is true, then we break. We'll have to introduce an exception for this. And this is gonna look really weird. It's like, not only are you breaking, but it has like a level that you can dial up, like, I don't know, like the amount that you're breaking. So you could break zero or you could break like 10 or something and maybe one is more than the other. But you're gonna have this kind of break statement. And then the other thing that I'm gonna introduce is the notion of a code block. Now this is gonna be a little strange, but it's basically like a nested set of instruction. Think of this as like curly braces or something or indentation. It's basically going to be a block of code that's like nested, okay? So you're gonna have this code block. And what I'm gonna do with the code block is essentially just try to execute it. So like do a recursive execution. And then I'm gonna catch that break exception. And then if the level is still high, I'm just gonna decrement the level and re-raise the exception. You're like, and so like, you're looking at that. What is that? That is like crazy town kind of control flow. Here's the thing that you get with that. It turns out that using nothing but the block and the breaks, you can implement like an if statement. This is what it looks like to implement an if statement. I'll move it down a little bit so they're kind of together. What you do is you just kind of nest two blocks inside like a block inside of another block. You put the test in there and then you put these like weird branch statements with a zero and one and here's how this works. Basically the end of a block gets a label attached to it. Like the end of the inner block is label one and the end of the outer block is label, or that's label zero and the outer block is label one. And then this ends up being like a go to, like go to one and go to zero. So you do the test and then if the test is true, you basically just bail on the rest of this block and you go to label zero and then you run the consequence and this thing does the alternative and you kind of branch out. Again, there'll be a quiz on that later, so kind of a while. And then you can do the same thing to do loops, it turns out. If you wanna do like a while loop, you introduce a loop instruction. Now this thing is going to be even stranger. I'm gonna go into an incident loop where I just try to execute a bunch of code and then right after I execute it, I break. And then I catch this exception and then if the level is greater than zero, we do the same little trick like that. Now what is that basically? Okay, so that is really crazy. What is going on there is a, let me undo that, insert. I have a few things to kind of speed up typing. This is how you would basically introduce a while loop. So if you had a while loop, like while test body like that, you end up doing it with like another, like this nested block idea and it turns out that these blocks basically have magic labels. It turns out label zero is basically the start of a loop and label one is like the end of the outer black. And like this thing here is like a go to zero. That's kind of like a continue statement. And this is go to one. And that's kind of like a break statement. Okay, so you have this kind of very strange kind of control flow going on where it's like, oh, okay, these are like raising exceptions and like doing this weird blocking and another stuff. The other thing that I'm gonna introduce in here is a function return statement that just basically tries to get out of all that nonsense too. So that is also going to be an exception. And I'm gonna catch that up in my call thing here. Basically that the return is just treated as like get out of this horrible mess that has been created. And okay, so you're gonna have this and it turns out that doing that allows me to write much more complicated programs involving looping and other things. I'm not gonna modify the original code per se, but this is what it might look like to execute a while loop. Let me kind of move this into position here. You would have like a much more complicated piece of code. Sorry, I kind of put that in the wrong spot there. But you're gonna have like these nested blocks and loops and other stuff. And what this code is doing is it's basically doing like a while loop where it updates the position. And then it's checking to see if the position kind of got too far to, you know, too high up. And then it's like flipping the direction and it's like making it come back down. In order to make that work, I need to add a few more instructions to the machine. Let me do that real quick. It turns out you can't do like if statements if you don't have things like conditionals, like relations. So you have to have like less than and greater than and other things here. So I'm gonna add a few little instructions here, like less than or equal to, greater than or equal to, like that. And if this is working, famous, famous last words, I should be able to run the machine and let me, okay, undefined variable. Okay, that's interesting. Oh, I think I didn't get my, I didn't get my machine set up here. Okay. Okay, let's try this here. Okay. You have to pass the local variables. Okay, a little bit of live debugging here. Okay. Oh, I know what that is. Okay. At least I think I know where it's, oh yeah, okay, sorry about that. Okay, so I need to pass the locals there. Okay, so let's try this thing. Okay, so now you see the thing like generates like a whole bunch of stuff kind of happened there. You know, it like cycled through a bunch of things. It happened fairly fast. I mean, I'm not really sure if it's giving the right answer, but you see the thing kind of cycling through instructions. Now the problem with this is that it's not, okay, so we've got like most of the makings of a machine, but it's a little bit hard to see it do anything. Like one of the things that I'm kind of missing is any kind of output from this machine, like any kind of display or anything like that. And in order to do that, maybe it would be useful to have like a Python function like that basically displays like a player or something. I mean, we're like drawing something on the screen. Maybe we want something like that. Maybe I'll put a little time delay on it just to like slow it down a little bit. Okay, do that. And maybe I want to have that something that I could, like can I execute that in my little simulated machine? This is some way to do that. And maybe there's a way I could have like an import function. This is an idea of having like an external function. It's not written in the machine. It's like embedding something externally. Can I have like display player to be like this import function of some kind? And can I have that in my function table or something? Now, can I extend my machine to do that? And maybe I even put like some, like a little extra instruction in there to do that. Maybe load X and then call this function to display. Okay, so you're gonna, maybe you want like a little import function like that. Turns out that that is not too hard to do. I can take the existing function thing that I just wrote, maybe give it like, give it something that you're calling, like have it like an import function. And then I'll just make the machine kind of look for it. Maybe here I'll check, if the function is like a normal function, then I'll do this thing that I had before. Okay, so there's the kind of the normal thing. And then if it's not the normal thing, what I will do is just get the result. Oh, hold on a second here. Okay, let me, yeah, if it returns, I'll do that. And then if it's not the normal thing, what I'll do is I'll just return the value of calling that external thing, import function. Okay, so I've got this like the little switch and hopefully if this is working, I will see like the output. Now it's real messy. I don't know whether you're gonna be able to see that, like with everything going on, but there's like a little thing kind of moving across like the bottom, like bottom of that. So it kind of went left and right and so forth. Now, you can look at this. Now as a kid, I was like, ah, this is awesome. You know, I was like, I don't even have the field of dots. And I'm already like super excited about my machine language game. But what happens is somebody will look at that now and they're just like, nah, you know, like my kids, like dad, this game is terrible. Like what are you doing? It's like, I mean, if we're gonna play a game, I mean, it's gotta be, I mean, it's gotta be like rocket game, you know, like in the browser or stuff and like, you know, shooting enemies and like we want like, we don't want your like text thing like going around, you know, it's like, what is that? You know, it's okay. So we want rocket game and so let me talk about rocket game for a second. First of all, this is not my creation. The link is up on the web there. And this is kind of a brave new thing. Rocket game is using web assembly. How many people have used like web, and have like either played with web assembly or know what it is and like two hands, okay? It's a web assembly. Now the fact that it has web in the name already like scares me off. I was like, oh, wow, no, okay. And then the other interesting thing is that rocket game is written in Rust. So the game is written in Rust. It's running on web assembly and it's in the browser and I kind of, you know, you look at that and I sort of realized that the web programming class where I learned CGI programming is just not, that is really not what's happening here, right? I mean, I don't even, it's hard for me to even like comprehend like what is going on with like Rust and web assembly, what is going on with that? And there's, and you might be inclined to just like, look at that, it's like, it's, you know, I'm sorry, it's just game over, Python. I mean, like time is up. You know, you know, just pack it in. I mean, I don't even, you know, it's like, what is Python's story for something like that? And so what I'm gonna try to do, I'm looking at the timer and I get some time. I guess the question is, is my time up on this thing? And so what I'm going to do or attempt to do is run that Rust program inside the interpreter that I just wrote because the thing that I just wrote actually is a web assembly interpreter. You didn't know where I was going with that, but this code is capable of running web assembly. So let me talk a little bit about like this setup here. So here's the problem, we're gonna, the clock is racing, the clock is, so web assembly looks like that. There's a program called program.wasm. I did not write this. This is compiled from Rust. It is a binary file. That game that you were looking at, Rocket Game is an HTML document with some JavaScript and it's a mix of JavaScript and web assembly. So this is kind of the thing that we're gonna try to do. And it turns out that this machine that I wrote can execute web assembly. Now, in order to do that, I have to make some changes to it. They're not huge changes, but let's talk about the changes. One of the changes that happens with web assembly is that web assembly is a very tiny, like abstract CPU, and it only understands four data types. Instant floats, 32 and 64 bits. I have imported these types from NumPy, mainly because doing so allows me to claim that this is a machine learning project. No, no, no. Yeah, it's, thank you. Some people were asking me, like, I don't know, we were having conversations with students and stuff, and they were like, I was like, oh, you should do stuff that makes people angry, and like doing something, like claiming that this is a machine learning project by importing NumPy is one way to do that. Okay, so, and I'm gonna put like an assertion on the stack push operation to assert that those are literally the only things that are allowed in the system. Like, I mean, you only have those types, and if you have anything other than those types, you are broken, okay? So, web assembly is, it's a little emulated CPU, and it only has four data types. The other thing that you're gonna have is it has a richer set of instructions. So, it has some instructions for creating constants. This is like the const thing that I had before. It has instructions for binary operations. These are things like add and subtract and multiply and divide and so forth. I have defined these as just a big table, essentially, of lambda function. There's nothing really magical going on here, just I'm trying to do it in a compact way. Okay, so there's a lot of binary operations. There are some unary operations. These are things like square root calculations, comparisons, and so forth. That is not a complete list, but it's some of them. So, you have some unary operations. You have some operations for loading from memory. So, it turns out that web assembly has these four data types, like ints, floats, and of different sizes. It has some different options for reading memory and different configuration. Okay, so I have some loads and stores, and it has store operation. Okay, so, mostly what I'm doing here is just inserting tables of like short little function. And the code that I wrote can be modified to work with that. The way that it's going to modify is that instead of me with my little minimal set of instructions here, I'm gonna check for some table lookups. And I'm just gonna dispatch off operations. Like, you know, if the op is a const thing, then I look up the conversion and I convert a value. If the operation is a binary operation like that, I'm gonna keep the code the same, but instead of doing like hard wiring it like that, I'll look up the operation and then pass it some argument. If the op is in unary, I didn't have any unary operations in the other thing, but like what you'll do there is push in like, you know, unary op, self-pop. Okay, so I'm kind of going through like by machine and just, you know, filling out some stuff. Do I have a typo there? I do have a typo there, okay. I heard the rumble that time, I was a little... Okay, good, good, very good, okay. And then, you know, you'd have an operation in like, you know, in the load table. If it's in the load, this is gonna be, I'm gonna do this in kind of a strange way. I'm gonna basically do load op and I'm just gonna pass it like a chunk of memory. Now, this is a total hack. Because there's nothing bigger than a 64-bit value, so I'm just gonna pass in like eight bytes and like see what happens. Oh, also the other thing with a load is they do introduce an offset. WebAssembly has like an address plus an offset, so I'm gonna introduce that. Store is gonna be kind of the same thing. Okay, so if you're in store, I'll pop a value. There's an offset that goes with that. Okay, that's an added offset. Am I missing something here? Yeah. Oh, oh, yeah, yeah, yeah, yeah, okay, yeah. That would be bad. I would be sitting here debugging. I've had like nightmares about this talk. Like if it goes wrong, it goes wrong really badly and it's kind of, okay, so you have like store operation. Turns out that there's a couple of other memory operations that are in the system. There's a size operation that just tells it like how much memory you have. And it's reported in 64K pages. So you have an instruction like that. There's also a memory grow operation. WebAssembly is actually kind of interesting, by the way. It treats memory literally as a big byte array. And what you do is you just kind of grow it and shrink it. I mean, you might be looking at this saying, there's no way, like that's like, like how can it be like so minimal like that? But like there's like a memory grow thing. We're gonna keep the locals the same. There is one extra little operation with locals called a T operation where you pull off like an item off the stack without consuming it. Okay, so you have that. And there's a few other additional little stack operations. There's a drop where you just pop something off and forget about it. And then there's also a select operation which is kind of the like the ternary operation, like a conditional kind of thing like that. I'm gonna keep function calls the same. I'm gonna keep my breaks the same. All that's gonna say the same. The block stuff is gonna stay the same. Actually, one thing with the blocks is they introduce a block type. I'm gonna ignore that, but it changes the offset that I'm using there. Okay, block type. And I think I'm basically more or less done with that. Actually, there's one other instruction that enters the picture. There is basically a tabled break instruction where you give it like a table of indexes along with a default. That is something that is used to implement break, like a switch statements. So there is a like a feature for that. You should be greatly disturbed by the lack of testing on this. This is awful lot of a lot of a lot of code. Okay, so we've kind of kind of gone through and modified it a little bit, but not a lot of changes. Now the claim is that that could run the rocket game. It could run the Rust program. Okay, now in order to in order to do that, we do still have this kind of problem of what like, okay, that's what WebAssembly looks like. How do I turn that into this game? Like how can I make Python work with that? Okay, so it turns out that that format is very easy to decode. It's like WebAssembly is actually really cool because they've actually rethought the whole concept of a DLL that might sound scary. Like if you know about DLLs, it's like, oh, good God, like no, like what are you doing? Like they've kind of rethought the whole concept of a DLL and decided like, what would we really like to have in there? So I've written a library to this is WebAssembly decoder. This is just in the full interest of disclosure. I wrote this, I'm incorporating it by reference because I don't have time to talk about it. But the way that you can work with this is you can basically just say, okay, I want to parse like a WebAssembly module and just grab this program, programmed out wasm. Okay, just kind of open it up and read it. And what happens with that is it's just gonna grab the modules and there's like a whole bunch of really useful stuff in there. Let me kind of show you what's in there. Okay, so I'm just gonna run that. Some of the stuff that's in the module is there's a whole bunch of information about type signatures. This might be a little hard to read, but it's like a big table telling me all of the type signatures of all functions in the module. This is already awesome. Like one of my early things in Python was writing the SWIG utility to do C extensions for Python. And one of the big complexities with that is that C libraries do not encode type signatures. They're not in there. Like if you make like a DLL or something that there's no type signatures in the DLL. And you're like, well, where are they? They're in the C header file. That's where they are. And like so I have to go write this whole parser to do C header files. And it's horrible and like it's horrible. WebAssembly right away, all the type signatures are there. Some other stuff that's really interesting about WebAssembly, it will tell you what needs to be imported. These are basically functions that are defined outside of WebAssembly and they have to be provided by like Python or JavaScript. It's kind of like that display player thing that I had. That's what's going on there. It has information about what is exported. And you have to type it right. Okay, then that's, it will tell you like what functions are defined in there that it's exporting to you. This is the kind of thing that I was again was like doing like the SWIG project. It's like, oh, I want to call functions. Well, here are the functions. It tells me the functions right there that it's like that it's exporting to the environment. It has code. I mean, you can come in here and pull off like the code for a given function. Like, that's not a very interesting one here. Okay, like, let me just kind of pull off some code. Okay, so there's like a fragment of code. You're like, well, that's not very readable, but it turns out to be very easy to parse that. You can say, you know, let's parse code. And then all of a sudden it turns into this like machine code that I just wrote. So these WASM modules, they basically, they have all sorts of cool stuff in there. It's like, you know, all the imports, all the exports, all the functions, all the code. And I'm going to use that. That's basically going to be the basis of my little web assembly encoder here. So one thing that I can do is build like the imported functions. I'm not going to totally type that in because I knew it would take a little bit of time, but essentially like the imported functions are things that have to be implemented in Python. Or JavaScript actually. It's just like what functions does it not know about? And so you're seeing some math functions here. You're seeing some things with like gameplay, like clear the screen, draw a bullet, draw enemy and so forth. Those are basically going to go into like a big imported functions table. This is exactly the thing that I did with the player thing. You know, I had like the imported function. I will have to import machine to do that. What I can do after that is I can declare all of the defined function. These are basically functions that are in web assembly. Like what I'm going to do here is I'm going to turn those into the functions that I did in my little hack this morning. You know, like before that it was just like, it's like, oh, okay, let's make a list of defined functions. What I'm going to do for this is you get a type index and a block of code. This is just giving you kind of an idea of what it looks like. Okay, so I'm going to take kind of two pieces of information here from the module. I'm going to look up the type signature based on that first value there. Okay, so this is looking up the signature. And again, this is the thing that's missing from like DLLs, like not having the signatures. This is awesome, I got the signature. And then I'm going to make a function. Okay, here's my machine function object. The number of parameters is going to be the length of the parameters of this thing. And then I'm going to, if it returns something, I'm going to just do a bull check on that. And then for the code, I'm going to parse the code, wadsy parse code, code instruction. Okay, so I'm going to make a function. I'll pen that. I'm going to make like a complete function table here. So I'm going to have all my imported functions plus all of my defined functions. Okay, so you're going to do that. So now, so what I'm doing is I'm kind of making like, okay, this is all the functions that are in this module. I have the Python ones that are kind of the, you know, they draw enemy and draw particle and stuff. And then this thing is basically all the, this is all the Rust code that I just did there. Okay, so whatever that Rust thing was, it's turned into my function objects. Now what I'm going to do is I'm going to get all the exported functions. Okay, declare exported functions. Do I have a typo in something here? Yes. Where? A typo. Yeah, yeah, yeah. I kind of like this, like this highlighting, you know, it's like, you know, the visual highlighting, you know, it's kind of, kind of, kind of awesome. Okay, so I'm going to make like an export table. This is maybe a little, little strange, but what I'm doing here is kind of going through the module exports. And then if they're function exports, I'm going to make a little table here. So what that is doing is it's kind of just setting up like everything that is coming out to me. And at this point, you're kind of ready to start making the machine, basically. I'm going to say, okay, make the machine with my functions. I'll give it some memory. Admittedly, that's a bit of a hack on the memory. I'm just saying, well, I'll give it like, you know, 20 times 64K for memory there. The file actually does indicate how much memory is needed, but I just don't want to deal with it. Okay, so make a machine, make some memory. It turns out that there's a step of initializing memory that you have to deal with. And that is also something that's in that web assembly module. There's like a little data section in there that sort of has like initialization kinds of things. So the way that I'm going to do that is I'm basically going to execute instructions to compute an offset. I'm actually going to use my machine for that. And then I'm going to go into the machine and set up some memory. Okay, initialize memory. Now, once we've done that, call something and live dangerously. Okay, now I'm absolutely terrified of this step here. So this game involves like a kind of a game board. Maybe there's a width and a height for instance. So they have to have some data types. Those types are coming from the type signatures. I'm not showing you that, but it's part of the exports. Let me just import the types here. What I should be able to do is basically just call like the export table and pass it in the width and the height and basically have some kind of prayer that this is like going to work basically. Okay, so what is happening is that that is going to try to call this, there's a resize function in Rust. That's written in Rust by the way. And we're just going to see if it works. I mean, if this works, this will be a miracle, but we'll see if it works. Positional follows keyword argument. Oh, well, okay, that's not, okay, we can fix that. I think I, come on Python, you're supposed to let me break the rules there. Okay, so let's try it. Is instance, okay, a few little bugs here in the code. It's not, at least it's not in the machine yet. Okay, let's try that. Oh no, oh no, worst fears. You're realized here, const ops args. Oh, in, in, in, okay, no, okay, I see it, yeah, okay. I think like the, it was the is operator, like not is, that there's a very different, definite distinction between is and in there, okay. Okay, so the thing is, okay, so I don't know what that did, but it didn't crash, okay, so I'm like, I'm only going to have like a two minute, two minute, I'm looking at like one minute, one minute 50 seconds on a timer here, okay, so it didn't crash. The lack of tests should be very disturbing on that, and essentially what you can do from here is like, well maybe we should just, maybe we should just have like a game loop at this point. I mean, why not, let's just go for the game loop. So it turns out that this rocket game, the way that it works is that you record kind of a time, and then the game loop records like the current time and calculates a delta, like what is now minus last, and then what it does is you call like exports on a, like an update function. So you basically say update on the time there, and then after you've done that, you basically call a draw function with no arguments. And keep in mind, those functions are written in Rust. I mean, they were written in Rust, they've compiled a WebAssembly, I'm calling them just kind of blind from Python, let's see what happens. Okay, so the thing is it's looping, I'm not sure what it's doing exactly, but it's not crash, I think the key thing is it's not crashing, that's probably the key part of that. Now, to see what it's doing a little bit better, I might go to my machine and turn off the print statement. I mean, a lot of the output there is coming from the print statement, so let me just comment that out, and then try this again here. Okay, so now what you're seeing is it's like, it's actually calling those Python functions, the import, these are the import functions, right? It's like, huh, okay, draw particle, draw NME, so forth. Maybe what I would really like to do is something a bit more interesting with those. Okay, let me come up here. It's like, those are not so interesting, maybe a more interesting thing to do would be to pump them over to Pygame. This is what kids like to play with in school and stuff. So I'm gonna load up Pygame. I've just re-implemented some of the functions in Pygame, so instead of printing, I'm drawing circles and circles and stuff. So doing the same, just replacing those functions. Okay, let's replace it with Pygame. If you're gonna do it with Pygame, there's a few things you need to do in the event loop here. You have to do a little bit of event handling. Let's just ignore that for now. And you also have to do a display flip. The way that Pygame works is you draw and then you flip the display. So let's put that in there. I don't know, let's see if that does anything. Okay, so now I don't have any way to play the game. So I didn't put any keybindings into the game. So that is something that you can do with, that's not easy, or that's not hard to do, but basically what I'll do is just check for some different keys. And I'm calling more Rust functions. There's some functions in there to toggle shooting and turn left and so forth. I'm just gonna add that in there. And then let's try play in the game again. Okay, so now what's happening is this thing is running in Python and I can basically fly around and shoot then. Just to be clear on what has happened here, I mean this is a Rust program running in a horrible interpreter in Python. Like don't, don't, don't, don't use it. I mean the whole thing is just running as this interpreted stack machine in Python, using Pygame, but the software for it is this Rust thing on the back end. There's part of me that just wants to say, borrow that Rust, you know, but, you know, sorry Rust, you're fine, you're fine. I don't want to start language war in the Python Tucker. But you look at that and it's like, that is sort of awesome in a way. And it kind of brings me, it kind of brings me to this, you know, this like future of Python. I hear people talk about, oh, what is Python's future? And like, it doesn't have a web assembly story and like what's going on with the types and all this, all this stuff. And I think like the only thing that I would throw out there is that this web assembly stuff is not well known, but it is super cool. Like if you were looking for something like weird, crazy project to work on that's like really kind of interesting. Look at the, I mean, here's the thing that's so amazing about web assembly. It almost has nothing to do with web programming in any kind of conventional sense, right? I mean, it's like web assembly is that, is that emulated machine. It's like a target for, you know, for like Rust and for C++ and C. And like you can compile stuff to it and you can make extension modules with it. And yeah, you can run it in the browser if you want, but you don't have to run it in the browser. I mean, there's actually a lot of kind of projects sort of going on right now that are, you know, that are sort of very interesting. I would have you look at it. One thing that I think was kind of a big inspiration on this talk is actually Omar Klein's talk from EuroPython. He actually did something with the same game. So he did something with Rocket, but also running like WASM in Python, but he was doing like some AI, like he wrote an AI to play the game where you have like a C program compiled a web assembly playing against the Rust program in web assembly, like compiled in separate modules and he had like some other stuff. So that was really cool. There's this PyOdide project, which is somewhat recent, which is like the complete Python scientific stack running in web assembly in the browser. There's this PPCI, I think it's pure Python compiler project, has some WASM support. This WASM or project, this is like a web assembly runtime that is not part of the web. It's actually like a standalone library. You can just like run code and you can run that from Python and a whole bunch of other languages. So I think the thing that I would just kind of leave you with in the talk is like, this is like an area that it just seems really wild and really kind of awesome and like an opportunity for just doing really neat fun stuff. And I've met a lot of like students at the conference and stuff who are like, oh Dave, what should I work on? Or what should I be doing? This is definitely something cool that I think could be worked out. There's a lot of interesting possibilities. And just by doing it, it was kind of maybe just kind of jump that hurdle of like wait, maybe it's not that complicated. That's kind of a very interesting thing. So that's the end of the talk. Maybe we went a little bit over, but thank you for, I've actually had a great time at this conference.