 Het is de tweede hier van de laatste 11.000. Dankjewel voor het joinen. Dit zijn onze eerste speakeren. Ze gaan ons vertellen over Brasspijten. Ik wil ervan aanwezig zijn om ze te winnen. Dankjewel. Oké. Goedemiddag voor dit morning. Dat is een actief. Welkom op dit talk. Wat we willen presenteren is... Wie we zijn? Wat is Python? Wat is Rust? Wat is Rust Python? En hopelijk geven we er wat demo's. Eerst, wie ben ik? Mijn naam is Wendel Bauman. Ik werk op Demkom. Ik ben een Python en open source fan. Ik werk ook op een andere project. PPCI. Check dat uit. Het is echt cool. Het is ook heel leuk als Rust Python. En hier zijn de links. Hallo, ik ben Shinglu. Ik werk nu op De Zone als software engineer. Ik werkte voor Mozilla op servo, quantum en Firefox. Dus, ja. Gaan we terug. Oké. Ik wil beginnen met Rust Python project. Wat is het? Het is eigenlijk wat het is. Het is het Python implementatie in Rust. We willen Python 3 syntax. De homepage is daar. We weten het al. We hebben nu al 19 contributors. Het project is alleen voor minder dan een jaar. Het is nog in een vrije fase. Ik weet het niet, maar het is minder dan 5% met Python, denk ik. Maar het coolste is dat we een web-assembly hebben. Shinglu zal het zien. Er is nog niet veel van de standardlibrer. Een vraag moet ik vragen. Waarom doen we dit? Een van de redenen is dat ik rust willen leren. Ik ga beyond and hello world programma, straks met een Python interpreter. Rust is natuurlijk safer dan Shinglu. Je weet dat. Het is ook leuk om alle details van de Python interpreter te leren. Het eindgool zou zijn dat we een Python interpreter hebben dat is safer dan de C-Python variant. Ik ga naar de rust-Python internals. Wat hebben we gedaan? Hoe werkt het? Ik zal zeggen hoe we de internals compiler-vm hebben. Hoe de import-system werkt en de built-ins. Dit is de overigere ontwerp. Het is geen verschil dan de C-Python. Wat het doet is dat we Python code nemen, we leggen het en we parse het. We krijgen een abstract syntax tree uit. We compileren dat syntax tree op bytecode. We interpreteren het in een vm. Als je een import-command ontdekt, gaan we in deze loop weer. Het is dezelfde als in C-Python. We hebben een paar rust-grades gemaakt. We hebben rust-Python parser, die alle door de source code naar AST heeft. Dan hebben we rust-vm, die is de meer rondtijdspart. Dan is rust-Python top-level-grades, die de twee verbindt. Dit is hoe we de code splitpen. Het is allemaal in één git repo, zoals nu. Ik denk dat het beter is om het zo te houden, maar we zien het. Hoe werkt het als we de legg-part doen? De legg-part is in Python heel moeilijk, want de legg-part is based. Het is moeilijk om een legg-generator te gebruiken, want je moet op de legg-part neemt. Het is een manuale legg-part, die alle karakters en produceren toekomst. De task van de legg-part is de source code en de toekomst uit. Dat is handwritten. Dan hebben we een parser, een Lullar-pop. Ik weet niet hoe je het noemt. Dit zal de toekomst opbieden en het in een abstract syntax-tree van je Python source code. Dit werkt eigenlijk wel goed. Dan hebben we de abstract syntax-tree, het is eigenlijk twee rust-enems. Ik weet niet of er geen code is. Wat er naartoe gebeurt, is de compilatiefase. We gaan de abstract syntax-tree, die we hebben geparst, en de bytecode genereren. Hier zie je, in Python kun je deze module gebruiken, in C-Python dat is, want we hebben nog niet in Rust-Python, maar dat zal eventueel edit zijn. Hier zie je een exemple van hoe een simpel functie in Python is transporteerd naar bytecode. Je ziet dat als je een functie hebt, waarin het A, B en 3 opbiedt, de bytecode zal load A, load B performant-add-operatie, omdat de Python virtual machine een stackmachine is. Hoe dit werkt, load A onder stack, load B onder stack, performant-addition, om twee dingen af te doen, opbieden en zaken. Dan loaden we de constant, dan hebben we de resulte onder stack en de constant en we doen de add en return de value. De bytecode die je ziet hier, op de rechtsbottem, is C-Python bytecode. De bytecode is niet standaard, dus in Rust-Python hebben we nog een andere bytecode. Ja. Waarom niet? Dus, misschien is het een id, ja, in .NET en Java, de bytecode is standaard, maar in Python is het nog niet de case. Maar misschien is dat welkom. Dan in de Python virtual machine, hoe we het in Rust implementen, het is eigenlijk een groot fetch in dit patch loop, dus het zal fetch een bytecode van de generatieve bytecode en wat is de bytecode en performe de operatie. En, als je ziet hier, als de bytecode een importinstructie is, zal we de hele loop weer invoeken. One interesting thing of Rust is is that we have Rc en refcell en we benefited from that because in C-Python there is reference counting, but Rust-Rc is actually a reference counting struct. So what we did is we defined a type py object ref, which is a reference count to the actual object. So in this way we used the Rc type in Rust to do the reference counting for us. And a py object, we defined it as a struct which it has a type, which is actually a py object ref again, because a type is also a Python object. And furthermore each object has a dictionary, so in Python you can set attributes and get attributes at will, so it's a really dynamic. And then for some Python types we need to store internally some payload. So if you have a Python string it's backed by a Rust string. An integer is now backed by big int which is also nice, so we have arbitrary integer precision. And bytes is a simple factor of bytes. That's pretty good. So this is an example of how we implemented the built-in functions of Python in Rust, because in Python we have a lot of built-in functions and in C-Python these are implemented in C but we of course have to implement them in Rust all over again. So this is an example of the all method in Python. I can show that in the demo later on. And here you see some the syntax of how you want to implement a function in Rust which is then exposed to the Python world. So when this function is called you will see that it has Python args as an arguments which contain all the positional arguments and keyword arguments as they are in Python. And then there is an arg check macro so someone made a macro for this which is very handy to check the types which you pass because Python is really dynamic but here we want to know what are the Python types of the args you pass in this function. And then we perform the functionality of the all method which is check if all the elements in an array are true or not. And then in the end we say return new bool and since Python has exceptions and Rust has not we created the pyresult type which is actually, it's okay or it's an exception if it has an exception this exception has to be propagated. So this really fits nicely on the Rust logic. Yes demo time. So if you want to run Rust Python you simply have to clone the repository and hit cargo run. All right. When you enter this shell you will see okay, you can do things like to the power 200. We have big integer support thanks to the big int Rust that's also one of the good things of implementing this in Rust. We can leverage all of the Rust crates which are already there. So this was surprisingly simple to do. I don't know how they did it in Rust. What can you do more? You can do list comprehension for example. So if you create a list like this for A in this will work. What also will work is if A is you can do I think you can do this. If A is bigger than bigger than one for example. So most of the syntax now works. So the part that's now to be done is implementing most of the standard library. That's really a lot of work. There can be a lot copy pasted probably from CPython. It will be a messy operation but in the end it will probably work but it will take time. And also some built-in objects are not yet complete. It's pretty far. I'll have to go on. So why we picked the Rust room and not the Python room is because join us in making this project because I estimated that it would be probably ten many years of work. So if I do this in my own it will be finished in 2029. But maybe it's finished earlier. I don't know. And also some challenges over the Python dictionary. So in the Python the dictionary each Python object can be used as a key in Python. And what we wanted to do was to use the Rust hash map for this dictionary. But the Rust hash map has you have to implement the equal traits and the hash traits in Rust. But the hash and equal function in Python return exceptions. And the equal and hash traits expect that the operation always is always success. So we're stuck. So any ideas from you would be appreciated here. How we can solve this. So we're stuck there so probably it will be a homegrown hash map implementation. And also the standard library is still a lot of work. And there's this project Uroboros which has a implementation of the standard library in Python. I want to use that. We'll see. So. With that. Shing. Cool. And besides the command line tool and the RAPL. We also have the web assembly build. So in the Rust room I assume that you might heard about WebAssembly already just to quick recap. WebAssembly is a low level assembly like language definition and it's binary format. That's now intended to run in the browser. Which can run at almost native performance. So it also works well together with the JavaScript. So if you have a web app that has some bottleneck performance bottleneck write that part in WebAssembly make it really fast. And they still work together with the JavaScript. So Rust compiler already have the ability to compile to WebAssembly. It has all the tools around it. Thanks to Ryan Little for helping us porting this to WebAssembly. He did most of the work. So the tool chain we used is the WebAssembly pack from the Rust team. They give you a WebAssembly bi-gen tool that can generate the bindings between JavaScript and Rust. So you don't have to write everything yourself. And there's also the WebSys there's also the WebSys create which exposes the DOM API to you. So you can use things like console log, accessing the DOM tree manipulating the DOM tree. And there's also the it's all wrapped in the webpack configuration so you can run webpack to compile everything. And we have a Travis CI pipeline that compiles the WebAssembly build, build a demo page and then push it to GitHub pages. So this is a rough idea about the workflow. So we have one create called RustPython. Which is the main create for the WebAssembly build. And it imports, it uses RustPython parser and RustPython VM just like the command line 1. And we introduce additional crates from the WebAssembly part. Which is the WebAssembly bi-gen, which generates the JavaScript and Rust Glucode and a WebSys that give you the DOM access. And we have some demo pages written in HTML, JavaScript, CSS and they're all compiled with WebPack. WebPack internally we'll call which turns our RustCrate into a Node module, an MPM module. So in our demo page we can just use JavaScript import import RP from that MPM module. And the whole thing will be compiled with Travis CI and push to our demo page. So to show you some we cannot show all the code but show some interesting part of it. So this is the main function we used in JavaScript to evaluate the Python source code. So the key part you can see is that there is a WebAssembly bi-gen attribute and it gives us a JavaScript name called PyEvel. So that means this Rust function will be exposed to JavaScript as PyEvel. So in JavaScript we can just call PyEvel of Python source code and internally it will set up the virtual machine compile it and then execute it in the virtual machine. And this is from the JavaScript site you import that MPM module we compile from Rust and then have the code in a string and then just call rp.py.evl We expose the rp to the global variable access it. We will talk about the standard out a little bit later. So there are some concepts in Python that doesn't match exactly to browsers. For example, Python print. How do you print something to a web console? So there are two ways we can do this. First we map that to the JavaScript console log. So as you can see in the web sys console this gives Rust the ability to directly call console log. So inside this we create a building function for print that calls console log. So when you call a print in Python, it will print to the JavaScript console. And for demo purpose we also wanted to print a standard output to a HTML element. So this is quite complex, but you can see we still use web sys. You can get a window, you can get a document and you can use query selector this oil Rust. And then you can set the value for that element. Let's see a demo. So here you will see we have a simple Python Fibonacci. And if you run it the output will be here. We can, we only print to 10 now. And you can see it runs pretty fast. Let's try maybe a hundred. It still prints pretty fast. And this is the one we use in the demo page. But you can use, or directly call it from a JavaScript. For example, you can call rp.pyvel and then give a Python code. So this will print to the standard output. We can try something like print2. So this is our thank you. You can check it out. It's on our GitHub pages. And for the future step of the web sys. First, we can try to do some replacement for JavaScript. There's already some project like this called Bryson. But it's like trying to recreate Python completely in JavaScript. So they have some performance bottlenecks. But since we have the WebAssembly bill, we can probably mitigate that performance hit. We can probably make a Python IDE in browser. Or we can try to do a like Jupyter notebook that runs completely in browser. There's something called iodite, which they compile CPython to WebAssembly en make a Jupyter notebook. We can also try this with RustPython. I can imagine that we have a lot of use cases in data science and all the AI related stuff in the browser. So thank you. And this is our project page on GitHub. And you can also find our GitHub pages. So check it out. Thank you. Questions? Sorry, I don't get the left part. So you said now we transpile the Rust code to WESM. And yeah, that is the whole pass. Your question was when we compile, when we ship that WESM build, what is in the WESM? So it's the whole parser in the virtual machine. Yeah, it's basically the whole parser in the virtual machine compiling to WebAssembly. And they have some using the WESM pack. They expose some of the APIs to JavaScript. So JavaScript and call it directly. Oh yeah, this is the WebAssembly binary in this 2.6 megabyte. So the question was how do you extend RustPython in Cpython you have the Cpython extensions in Python is an interesting story that was Cpy X. So I think what that does is it mimics the C API which Python provides to extensions and couples that to Pypy. Probably we will do the same, but also I think we will have two extension mechanisms at some point. But none of that is there right now. So at this moment it's not possible. But I think that will come when we have a possibility for Rust extensions and a possibility to load existing Cpython extensions as well. That would be great at least to my opinion. So the question was if you start from scratch is this a good opportunity to do sandboxing right and right? I didn't think about sandboxing but if you look at the Cpython code it is a 20 year old code base logically there is legacy there. So this is a good opportunity to start afresh so to say. So there is some things in Cpython which may not be nice. I think we look at how can we make it in a good way in an improved way where we can. So probably it will not be 100% compatible in the end with Cpython because we didn't implement some quirks of if you want to call it that way. Sorry to answer that also to be very honest we are not like super language experts so we didn't think about ok if we start from scratch we can get all these benefits it's more like a learning experience so we start from scratch because we want to learn both Python and Rust.