 The sponsored track, they put it all the way in their coins. So I want to talk to you guys a little bit today about Skylight, although we really did shangha this talk and turned it into a rust talk. Since it's a little bit about Tilda, we started the company back in 2012, and we're really pretty proud, and we work on a product called Skylight, and DHH's message yesterday about being like a small team, and needing to put tools into your backpack that are going to let you compete with the big guys, actually really resonated with us, because we only have five engineers on staff, and we're building products that compete with companies that are IPO, or are probably IPOing, yes, like very much much bigger competition. And fundamentally what that means is that we need higher leverage tools. So when we built Skylight, the thing that we really wanted to solve, the thing that really put a fire under us was that all of the tools that we were using to measure the performance of our applications were recording averages, and as DHH said, it's a visit of DHH's blood test to make up for my Twitter feed yesterday. So DHH wrote this really great blog post in like 2007, it's like an ancient times, where he said our average response time for basing up right now is 87 milliseconds, which sounds fantastic, and he believed you to believe that all is well and we wouldn't need to spend any more time optimizing performance, but that's wrong. Average numbers are completely skewed by tons of super fast responses to feed requests and other cash requests. If you have a thousand requests that return in five milliseconds, then you can have 200 requests taking two seconds and still get respectable 170 milliseconds average, useless. And I actually think it's worse than useless, I think it's accurately misleading. So instead what we need are our histograms, we're like, great, we have received this wisdom from DHH, so let's go build a product from it. So that's what we did. We built a product where instead of giving the average, you can see a histogram and this is super important because looking at a histogram makes something like just a little obvious, like you can see cash hits and cash misses because of bi-model distribution. You can also see the 95 percentile, which is, gives you a much better sense of what the average worst case that your customer is experiencing. And we did that all using very high leverage open source tools. So our back end in particular is built on a product called Hatchestorm. I don't know if you can read below. It says distributed, resilient, real-time. I wish we had known when we figured that that was a pick-two list. Carl had a road to get. Anyway, you may have seen our talk. Right, if I grab a slide, I apparently grabbed all the animations that come with it. But we gave a talk on our, so this year we want to talk about a different high-level tool, which is Rust. So our tagline for Skylight that really motivates us is how do we give our users? We just don't make a bunch of data on them. How do we give them real answers so we can be set to do all the data that they don't have to? And as it turns out, doing this answers not data approach requires a lot of data. We have to collect so much information. And when we wrote the first version of our agent, which runs inside of your application, we wrote in Ruby. It's really great, you know, Ruby. But we quickly realized that if we were going to collect the amount of information that we needed to build the product that we wanted to build, Ruby just had some fundamental performance problems that weren't going to be acceptable. But we really needed something, but we really needed a tool that was going to give us global-level control, like a C or a C++. But we were afraid, because Yvette and I were afraid of mediocre programmers. And we know that we're giving our software to run inside of your application. And the idea of us writing something with like a segfault that would crash your apps is just like totally terrifying for our application. So we needed something that would give us the high-level safety guarantees of Ruby, so we built this low-level control and this low-level access. And then Rust was the answer. Rust came out, it was still 3.1.0. But we decided to make a big battle in Ruby, well, 2.0. We've got a semantic version of Ruby, so we're here. So we decided to rewrite our agent in Ruby, in Rust from Ruby. And we called that our featherweight agent. And this, I have to say, has been one of the best decisions that we've made. It was very nerve-wracking to bet on this 3.1.0 program line, which is low-level, making all these quite intense promises. But it's been really great because Skylight, the agent now, in addition to collecting so much more information than our competitors, just sips resources in comparison. Because we're writing this code that's essentially operating like C, in addition to better performance and being so lightweight in terms of resources, it also lets us build features that we would never be able to build if we didn't have that low-level access. Being able to write something in native code lets us go a level deeper into MRI itself. So, for example, this year we launched a new feature that actually shows allocations. So you can actually see how much memory is being allocated in your real-time production, which is huge when you're trying to track down memory issues. And we can do that at a really granular level, as we drill down. Yeah, play it to the minute. And this is also letting us check the new feature that we're announcing today called Trends. So Trends is a new weekly email that we'll be able to subscribe to, we're launching it this week. You'll get a weekly email showing you not just negative percentile but also your median. So this is a really great way to protect changes over time. So the thing that I was asking you to do is going to get into the mean of the whole matter. But the thing that I was asking you to do is with a language that offers you low-level control but high-level safety and expressiveness, if you're a small, proper team, what can you do? Like, what new opportunities and new features in your apps does that involve? Well, for the new area, it's Kuda with his rush field. Okay. So those kind of colors and the rusts, oh my god. Oh, you came up with colors and the rust colors. Uh, there's like a... Oh, yeah. Let's do this. All right. I can hold it for you. Okay, so today we're talking about rusts. This is the Rust logo. I do a plot program like you just saw on this expressiveness and speed graph. And I actually kind of find this to be a somewhat pointless exercise. And I use JavaScript as sort of an example of this, which is that, you know, when I started writing JavaScript in 05, JavaScript was pretty bad at expressing this axis and even worse on its speed axis. But there was one thing that people underestimated about JavaScript. And what they underestimated was the fact that JavaScript was everywhere, right? So JavaScript was, on the client side, basically all you got to write. So you wrote a lot of JavaScript on the client side. On the server side, it was very tiny. You could write one there as rails or something. Yellow is PHP. So JavaScript was everywhere on the client side. It wasn't very popular on the server side, so people kind of dismissed it. But they sort of missed the ubiquity of JavaScript on the client side. And what happens when there's an advantage like ubiquity is that people go and they say, okay, well, JavaScript is low on its speed and expressiveness scale. Well, let's write V8. We write V8. Boom. Now it's way faster. Oh, people don't think it's expressive enough. We'll go and we'll make it more expressive, right? And so this idea of programming languages as living in fixed places on an X, Y axis of speed and expressiveness is kind of not the way I think about programming languages. I think about programming languages and tools in terms of enabling what they enable. So obviously, everyone in this year builds your rails. And for a lot of people, rails enabled you as a person who may not have necessarily, at least for me, I'll speak for myself. So when we didn't really know what I was doing we needed to build pretty ambitious stuff that I wasn't able to build before. We were running for a simple reason. And the thing that was great about Node, I think, is that Node allowed a bunch of people who only knew how to write in front-end, but like 99% of people write in front-end using JavaScript to let them write back and stuff. And a lot of people like to say, like, oh, do you really want those jacquery jockeys right on your server side? And that's like a pretty good joke that you can tell. But the industry is actually controlled largely by a lot of people who you may not necessarily want to be building that thing, but end up getting Preston's service. Like for me, that's definitely my story. I got Preston's service and do a lot of things I wasn't ready to do. And so for me, looking for a technologist that enabled me to do my job is so important. So what Rust is really good at, Rust is not ubiquitous by any stretch. But Rust actually enables people like you and me, Tom, to be systems programmers. And usually when I say that, I say, oh, yes, Rust will enable you to be a systems programmer. I get a little like this. Like, I'm not a systems programmer. What are you talking about? Somebody else can be a systems programmer. Although as Tom pointed out, sometimes you don't have a choice. But then usually when I get asked that, I say, no, it's like good. You may want, may end up in a situation like that. People say, oh my God, like, that sounds really scary. It's a program. It sounds like super hard. Obviously, I played the C a few times and that was crazy. And also I said all the other times, they were super dangerous. So then you're like, no, Rust is great. It lets you, you know, it's easier. It has some of the high-level affordances. It's also not as dangerous as you, as C, it's like safe, actually. And then people say, like, oh, it's a systems programmer. It seems cool. But like, what is that? Like, what is a systems programmer? So what does that mean? What is the definition? So there's actually a lot of definitions, but I'll just give you my personal take on it. So there's like a few different things that systems programming means to me. One of them is you get to write code without a GC. And there's a lot of reasons why you might care, like if you're a high frequency trader, you care about GC pauses. If you're asked, you don't want to invent a GC language inside of a GC language. So there's a lot of things you might want to program without a GC. Also programming directly against the metal. I don't mean like the way no people say programming on the metal. I mean literally like writing against the lowest levels of abstraction that you have access to. And doing that without additional costs, additional abstraction costs. You shouldn't have to write extra layers or have extra layers of costs just to program and talk to the criminals, right? Also, in terms of runtime, most programming languages have a pretty heavyweight runtime or an involved runtime. Usually when people say systems programming, what they mean is that there's like either no runtime at all, or the runtime is very lightweight and is pay as you go. As you need it, you can use it. Also, this is like our thing that came out of C++, but I think it's important is like you should be able to write abstractions, and those abstractions should not cost. You should be able to write functions. You should be able to make structures. You should be able to organize your code in a good way and not have those abstractions at additional costs as you go. And finally, I think the thing that systems programming most is is everybody's written code, like you write a review code, and normally the good answer to Rust is like, well, it doesn't have to matter. Who cares? I'll just write my Rails app and it will be fast enough and it doesn't have to matter. But occasionally you end up writing code where it doesn't matter. It happens basically in every app where there's a performance critical area and it just doesn't end up being sure anymore that it doesn't matter and the amount of time that it takes you to get to a reasonable performance is actually more writing in a language like Ruby than writing in a language that's optimized for a good performance. So that sort of for me system programming is when it turns out that the story that we tell ourselves about performance is not mattering for the cases where that doesn't end up being true. That doesn't mean a bunch of stuff though. It doesn't mean malignant free. It doesn't mean you have to write assembly languages. It doesn't mean you're writing code that only talks to Unix. It doesn't mean you're writing handcrafted make files. It doesn't mean you have to care much about what the linker's doing and it doesn't mean that your entire application is written in the system's programming language. It may mean that you're writing using a little bit of system's language for errors or it matters but most of your apps are still written in something like Ruby. So a good example of this like Tom said is Skylight. So Skylight basically used Ross because we needed to embed a programming language without the programming language and two GCs is not good. We needed high performance and we need low memory. So for all those reasons we ended up going with Ross. Firefox, sorry, Mozilla actually is using building Ross for kind of a different reason which is that they're building a new browser engine called Servo and for them they needed to build something that was fast, safe and parallel so they really wanted to be exploring different parallel options and interestingly the Servo team is like seven people so you want to talk about a prepper team or five people building Skylight, that's seven people building a browser. And they're using Ross because it allows them to explore ways of writing a little of a code that you can normally write C++, you know you can normally write Ross and C++ but less than we explored that high performance profile about being able to do parallel stuff. So that ends up being pretty important. So those are all reasons why you might use Ross. I'll talk a little more at the end about Ross and Ruby. But before I talk about Ross and Ruby I want to talk a little bit about how it works. So I'm going to talk about Ross but before I talk about Ross I want to talk about sort of how the garbage company works. So here is some Ruby code. You can see I have a very simple structure. I have a class as a point as an x and y. So Ruby audience so you should know what this code does. It's very simple. And I have a link function. The link function basically makes a new point. A couple new points makes a line and calculates the line. So what happens is I go into this link function, right? I make this point. The point is to be created. It goes into the heap somewhere. I make another point. No problem. It goes into the heap somewhere. I make a line. It goes into the heap. Of course that line points at the two points, right? I go into the link and then at some point in the future so that those objects stay there chilling out. At some point in the future something stops the world and it goes into that and looks into what's going on and discovers nobody else to use those objects anymore and includes them all. And that's actually a pretty good story for safety because basically by definition a garbage collector ensures that you can't use an object. Sorry, the object is clean up. Only after is no longer being used. So the whole concept of a use after free bug is impossible by definition, right? You have a garbage collector. Use after free is impossible. Free only happens after use is done. That's the point of garbage collector. But that means that you need a garbage collector. And there's another way of dealing with memory that is how the methodology for using memory, for dealing with memory, C or C++ and that methodology is called ownership. And the idea of ownership is basically that whoever allocated the object is responsible for de-allocating it. So if I make the object, I have to de-allocate it. And the reason why this is good obviously is that it means you don't need a garbage collector. The reason that it's bad is that now you don't have to keep track of all that. You have to make sure that you do the right thing. And if you do the wrong thing and I make the object and optimize to create basically game over. Now I try to use it later and I get a cycle. So the idea of my ownership is how is the methodology for doing systems programming but historically actually doing it was very hard. So let me try to give a simple analogy. So let's say there's me and there's Carl in thinking man pose and there's a book shop. I basically go to the book shop. The book shop says, okay, here you can have a book. It's my book. Now it's my book. I bought it. So now I bought the book from the book shop. Now I'm allowed to destroy it or burn it. Not the best analogy. So I'm a good use of the blame energy. So because I own the book I am allowed to destroy the book. It's my responsibility. I don't have to ask anybody else for permission. Now once I own the book once it's my book I can also give it to Carl and now that I've given it to Carl Carl is allowed to dispose of the book but I can no longer dispose of it. I've given it to Carl it's now Carl's book. So one way that you might think about this is that ownership both in the real world and in the programming world is basically talking about the right to destroy something. So let me show you basically the equivalent code. Hopefully people can read this code. Probably not, but sorry. 1024 by 760. So you can see on the top that there's a book. It's simple if you're like familiar with any type of languages, right? It's a book. It has a title, it's a string. It has a bunch of chapters and some vector of strings. Then we have a function called main, right? And I'll just walk through what happens here. So what happens here is the first thing is we say now read the book out of the file system and then now the book exists and it's owned by this function. So ownership of the Rust is usually rooted in a function. So the function that's in the middle of being called on the book. Now I go and I print the book and that's great. The book has printed to the screen and now I leave the function main. So now the function main as an owner doesn't exist anymore and because the function main had the right to destroy basically Rust will automatically go and clean it up. So you didn't have to do any work. You should know the lack of manual memory management here. What happened was that because the function main owned the book and the function main doesn't exist anymore the book gets destroyed. And that's, I think that's a pretty good starting point if you want to try to do automatic memory management. But of course, if only the function that ever created something is allowed to use it that doesn't make it very interesting programs. So let's look at a little bit of a more involved, a little more formal example. And this is an example where I did, the main function makes the book and then it calls up the print book function to print the book. And so what happens here is that we make the book as before. Now the book is owned by the main function. Now we call the print book function and the thing to note here is that the print book function just takes the book, capital B book, no extra signals or anything like that. So because of the fact that it takes the book by default in Rust that means you're going to transform it. And now what that means is that the main function no longer owns the book. Instead of the print book function owns the book it does the print line as before and when it leaves now it is responsible for disposing of the function and the book gets destroyed as you might expect. Now you might be thinking okay so that's cool but I've written a lot of Ruby and if there's nothing really stopping me in Ruby from actually falling print book going and using the book again. So if you follow this methodology over here what's going to happen is that the main function is going to try to access a book that was destroyed and we said before that we can kind of get a car responder to deal with that kind of problem. So how does Rust deal with that problem? So let's go back and look at this example where we do the same thing as we did before but after transferring the ownership to the print book function we try to use it there we try to print the number of chapters. So as before we make the book you know we put it it's owned by this by this function the main function we print book we transfer it as before the book got destroyed now we try to go back and print the book well actually no what's going to happen is we didn't actually get this far the compiler actually discovered that we did this ahead of time and what it says is you use the moved value the value is transferred the ownership was transferred into print book and you're trying to use it and you get a little note that says no the book was moved here so in the real output there would be a little arrow pointing at the print book function so you say okay I see that I transferred the ownership I'm not allowed to use it anymore and sort of like I said before so this is I think this is fine for simple examples but you can sort of think to it that this is not the whole story this is not you can't really write interesting programs and the ownership of the function that wants to do something with it that's not that's not very intuitive and to deal with that in the real world in the real world of transferring ownership we deal with that by saying you're allowed to lend something so I go to the library the library doesn't have to give me ownership of a book you can lend the ownership to me and then I'm giving a promise to the library that I'll return at a certain point so the way we deal with the problems in the real world is by borrowing that's also the way that we deal with the problems let me give you an example so I have this book that I got from the library and I say to Carl hey I'll give you this book but you need to return it to me by 5 PM on Friday right and as long as Carl returns it by 5 PM on Friday everything's great now the problem is that in the real world there's nothing enforcing that rule so I can say to Carl I'll give you the book back at 5 PM and then he doesn't give you the book back by 5 PM it's basically now I'm in trouble if somebody else wanted it for me then I'm going to be in trouble but of course let's look at another example with borrowing and you're going to notice that this is basically the same program that we wrote before except this time when we call print book we use the ampersand symbol before the book and we put an ampersand symbol before the capital B book on the bottom and the only thing that we're saying here is different from before is that instead of transferring ownership from the main function to the print book function we are lending the book to the print book function and it's required to give it back to me at the end and that happens automatically so let's look at so I start off with the as before the book is owned by the main function but now because I call print book with the ampersand it gets lent to the print book function the print book function prints the thing to the terminal and then when it returns it gives the book back to the main function and now because of the fact that the game is booked back to the main function when I go to print a line the main function still owns it it can happily do that and everything goes along pretty nicely but there's one additional step that you need to understand how the whole system works which is the fact that you can borrow you can lend something that you borrowed to somebody else we call that some leasing the idea behind some leasing is that the first person to borrow isn't the last person to borrow so in the real world you can imagine I go to the library the library who lends me a book and the library says hey I need you to return this book by 5 p.m. on Friday great so I remember that I need to return the book by 5 p.m. on Friday and then Carl says to me I want to borrow the book so I can give Carl the book but I can say to Carl hey I need you to give me this book back by 4 p.m. on Friday because I know I can give you a batch of the library by 5 so you can borrow the book but you need to return it back to me then Carl returns the book back to me I return to the library everything's great again in the real world it starts to get complicated in the real world when you start dealing with some leasing you start dealing with complicated some leasing arrangements and restrictions and that's mostly because in the real world people are very bad at but in the programming world the compiler can enforce it for us and so let's look at another example with some leasing that solution was a little more involved so here the important thing here is that we're able to write arbitrarily involved abstractions just like in any programming language as long as you follow these basic ownership rules so here's the function called main again we're going to get the book the book is going to be owned by the main function and then we're going to call print book and then we're going to lend the book to the print book function so it gets the book it already has真的很 but he doesn't really go had the print thing so it's going to delegate that to print title function the print chapter function right so it's going to call print title that's going to lend the book to another level down it's going to leave that's going to return back up then the print book function goes to another level is going to print to chapters that's going to go get the as soon as the whole main function is done, then it can destroy it. So the really cool thing about all this is that in all these cases, I think the way, the thing that we're doing is pretty normal, right? It's basically, you think about it in most programming, when you call a function, you're basically lending, you're not expecting the thing that you're calling to take ownership and try to do something with it later. But we have to pay the garbage collection overhead in all programs, all the time, in all cases, because somebody might want to do that, right? And in Rust, the way it ends up working is that you start off with this assumption of ownership transfer, and you can lend things as much as you want. That's basically a thing you're free to do. And once you've done that now, we can completely eliminate the cost of garbage collection across the entire system. So there's one last video, which is immutability. So far, we've been talking about read-only things, and of course, you can imagine that if you're only dealing with read-only things, you can lend as much as you want, anybody can look at it, and of course, they can't mutate it, so it's totally fine. You can have 50 people looking at something at the same time, and it's fine. But what if I want to allow mutations? Mutations add a little bit of a wrinkle to it. So let's say I go to the library, and the library says, here, you can have this book, and you can feel free to change it. Let's say you can move the book around, or fold the corner, or something like that. And then Carl says, hey, I want to borrow the book. I might want to say, Carl, you can borrow the book, but I don't want you changing it. And so I can say, hey, return the book on Friday, but don't change it. And he returns the book, I return the book, everything is great. Again, human terms is getting even more complicated, very difficult to implement the rules. In rustics, again, it's pretty strict or changed to what we've been doing all along. So the first thing to note is that so far, by default, everything you do in rustics is quote-unquote immutable. But when we say immutable, we don't mean that the object is frozen, there's no runtime jet, something like that. It's just by default, if you have a reference to some kind of object, you're not allowed to mutate it, the compiler will prevent you from changing it. Now, let's say I want to add a new feature here, which is that I have the ability to add a bookmark to, to the book to say where I want to. So now in order for me to be allowed to mutate that bookmark, I need to start off by saying, give me a beautiful book, don't give me a book, or read only book give me a beautiful book. And that's fine. And now when I call the print book function, the print book function, before I just call it the ampersand, which means I'm lending it to you, this time I'm calling it with the ampersand mute, which means I'm lending it to you and you're allowed to modify it. So I call print book with the mute, I send it over. Now the thing to note here is that when print book calls print title, when print book says I am allowed to mutate it, but I'm printing the title should mutate it, so I'm not gonna let you mutate it. And so print book or print title, which was before, right, it follows it, does the thing, call print chapters, does the same things as before, right? And then at the end of my function, I'm basically gonna go on, I'm gonna mutate the bookmark. So this is a kind of a hokey example because print book shouldn't be changed to the bookmark. But the key point here is that if you look at the main function, it's clear to me that the print book function might be mutating something. So just by looking at that signature, I can say, okay, I can see that mutation might be happening and all the other signatures on this page don't take a beautiful bar or something. So we know that they can't mutate anything. And that ends up being pretty important. That ends up helping a lot. So now I'll just recap by saying there's basically two rules of borrowing. You can have as many outstanding read-only bars as you want, so you can, in the real world again, you can't give the same book to many people at the same time, but on the programming, you can have as many pointers to the same object as you want, so you can have as many outstanding read-only bars as you want. But in contrast, a mutable bar is unique. If you have a mutable bar that's outstanding, no other bar is mutable or read-only can occur at the same time. And again, it's very important to know that this is not enforced at runtime. It's not like every single time you try to borrow something and check to see if anybody else has anything outstanding, there's no like mutable locks at runtime. It's all enforced by the compiler, but this gives us some nice problems. So I want to show you some examples. So I talked about what's a lot of, it's not a lot, I want to show you some examples of what that might be like. So we start off here, we have this function called sync. And the sync function takes two books. It follows two books, right? And it just says the title is the same as the first title is the same as the second title or the chapters is the same as each other. And across the double equals does what it does for me, it does a deep comparison, right? And if you call sync with book 1, book 2, obviously that's fine, right? I'm allowed to lend something to the same function. These are two totally different books, so that's totally fine. Now, what if I, instead of lending book 1, book 2, what if I call sync with book 1 twice? So again, because this is a immutable borrow, because it's a read-only borrow, this is still fine, even though I'm making two copies of that book. So for the perspective of the same function, those are two copies of the same thing or two different things. The fact that it's read-only means that's safe and you're allowed to do it. So that's still fine. But now what if I make another function? What this function is gonna do is give me a copy and it's going to take a book and immutable book and it's gonna copy the read-only book's title into the immutable book's title. So here what we did is we said, copy the title from book 1 into immutable book 2. So like I said before, that's still totally fine because in this situation, we have book 1, we have book 2, we're not, there's no elixir going on, we're following the rules for borrowing to immutable borrowers must be unique. That's totally fine. Now what happens if I'm gonna change it? Now I say, we're gonna only get one book and then I'm gonna call sync copy from book to the same book, immutable book. Again, from the perspective of the copy function, it doesn't know that these are the same thing, right? But what it ends up asking is a pile of books with this and it says, you're trying to have a read-only borrow and a immutable borrow at the same time that violates the rules of borrowing. So error cannot borrow a book as immutable because it is also borrowed as immutable. And it gives you a note that says, the previous borrow of a book occurs here. Okay, this is useful. And then it says the previous borrow ends here. And basically at the end of the day, borrowing is a secret sauce of, trust me, borrowing basically allows you to do very, very involved, complicated, recursive things that you might think you need to borrow each one through. But by following these very simple rules, you get them when you need to get them. I actually wanna skip a little bit here because I wanna get to Ruby's part. I'm gonna skip over the closure or stuff. But the TLDR on the closure is that closure is called the same rules as regular, closure is called the same rules as regular. So if you're using a closure and a closure closes over a variable, it ends up having the same rules. So if you pass the closure to another function, and the function tries to call multiple times, that would violate the ownership rules and then something gives you an error. You can learn more about that in the rest of the book. So what about the currency? So the interesting thing about the currency that really the currency boils down to one thing, which is that shared viewable state is the root of all evil. And there's basically two strategies that people use to try to deal with this problem. So one of the solutions is called channels. The idea behind channels is that you're not allowed to have two copies at the same time. If I wanna give value to some other thread, I have to pass it to a channel and you basically can't get it. Another strategy that's used is functional style, which is that you can't mutate. You can never mutate anything and you won't be in our shared viewable state. Ross sort of does a combo. It says you can have shared state or you can have a mutable state, but you can't have shared state that is also mutable at the same time. And if you think about that, that's actually the exact same idea as the original rules of borrow that we just had before, which is that you can add as many outside and read only bars as you want, that's shared state, or you can have a single mutable borrow, that's mutable state, but you can't have both of them at the same time. So you can have alias state, or you can mutate, but you can't have both at the same time. And if you use more Ross, you'll see that the send trade and the same trade are basically the ways that internally Ross enforces this. It's not anything special about threads or anything special that any particular bad structures across. There's just two trades that represent threat safety essentially, and any library that's written like Carl has a bunch of libraries that do Eastern Corniceo currency, and they're able to implement these rules themselves. Fair enough. Just a couple of simple examples here. So we have the spawn function, the spawn function takes a closure here. You can see that if we call the spawn function, and we try to access a book from the outside, it's going to tell us that there's an error, and it's going to tell us that the book doesn't look long enough. And the reason for that is, I actually have this kind of as a dependency on the closure and stuff, but the basic idea here is that the closure can run at any time, right? So we call it spawn with the thread that closure can run at any time in the future, but we know from before that the main function owns the book, right? So we can't let the closure run and use the book at any time in the future, because we know that as soon as the main function gets exited, it's going to clear the book. So that's an error, Basie says. Book does not look long enough. This is compiled by an error that we add the word, but we add move to it, that Basie says this closure's going to be moved out, you can feel free to move anything from the outer scope inside of it, and then that becomes just a regular transfer of ownership into the closure. I'm going to skip the next section. So one thing I didn't talk about, or seriously think I didn't talk about is sort of high level productivity, and maybe you got a sense of that from the one slide that I showed the closures, but for us have a lot of higher level ideas that are pretty familiar to higher level programming people like people coming to Ruby, high level JavaScript, so there's things like Ho-Oh, right? So you can have a type and you can implement it. There's things like traits, which I don't have an example of, but the idea behind traits is sort of similar to Ruby Mixins or Ruby Group requirements, which are like still Ruby Mixins, so you can write these like happy support where you can implement like a, you can implement a method on the one function, on the one value where you can implement, you can say like one of that things that I go, or you can implement traits that go interfaces, right? So there's sort of this very flexible way of dealing with a mixed type of situation. There's also erasers, which are a way of doing something that looks very Ruby-ish in the sense that you might map, filter, reduce over things, but under the hood ends up being profiled to being effective as fast as the things that you would have written by hand, and that would just sort of match all of the M stuff. There's also enums, which is if you're familiar with other languages where there's like something with a variant. You can have enums, but you can also put methods on this one now, which is awesome. There's also over over over operators, which is pretty great. It's going to do things that look interesting, so you can over over like indexing operator, or also things like the plus operator. So all that's pretty cool. I didn't talk about it because it's not like, these are all like cool things about Rust, but they're not part of the big story. The big story is that ownership lets you do really low level things without the fear of cycles that you have. And I wanted to show just a really quick demo before my time is up of what that might look like in Ruby. So let me, I should bear on my screen. So I don't have much time, but basically, I look, make it bigger. Oh my God, this is the biggest space. So basically I wrote a little, a little rack handler. So this is a rack handler you can see through me. The thing on top here is kind of the distinct part of this, which is I'm using a built-in thing in Ruby Fiddle, which Erin's talking about a lot. And I'm basically just saying, okay, I want to load, I'm going to dynamically load this Rails conflict that I got from Rust, and I'm going to define three functions, a anchor function or a port function who takes an analytics and a analytics function that returns an analytics. I made a little classical analytics which just wraps that so you can see it initializes the calls you have to buy, players, it's basically calling into Rust. So all these things that are happening here are calling into Rust. And then I wrote a little rack handler here, which is just an analytics handler. And when you go to slash report, it calls report, it gets this right back. And otherwise it just increments because we're a bunch of URIs. If I go into the Rust code, you will see that the Rust code is actually pretty vanilla Rust code. I have a structure here called analytics. It has three hash maps in it for host schemes and end points. And then when you call anchor, it basically goes, okay, increment, parse the host, make sure everything is okay, basically failed the inside of the value URI. And then increment each one of these three hash maps with the information pulled out and then also increment the token. So we basically have some Rust code that does what we wanted. Now the cool thing here, the really interesting thing here is that you see this, there's this no manual thing and then pop-exter and see. Other than this, it's pretty vanilla Rust. But by adding these descriptions here, what we're basically saying is from the perspective of any other program that really does not want us to treat this like C. So you can see here, for example, this interfunction takes an analytics and a buffer. And if I go back into the, if I go back into the config.ru, you'll see that that's, interfunction takes a C point of analytics and a buffer. So the cool thing about Rust is that even though it has all these high-level C guarantees and syntaxes in exactly like C, the underlying semantics, if you can tell Rust that this should be usable from C, are exactly the same as C. So now let me just run. I should actually show you so Rust has this thing, Rust has package manager. So there's cargo.toml, which is the package manager description. You can see I have a Rust Conf demo, I have some authors. Then I have, I describe my library, I say it's a dilemma which is important for this demo. And then I say it has a dependency on URL and it has a dependency on Ruby Bridge, which is a library that I wrote for this demo, which is basically just the thing that gives you the buffer interaction. And then if I go to cargo.bill, that's release, it actually does nothing. And the reason of that, if I run for code, is that it sees that I already built that. So if I RMRF, the target directory, and then run cargo.bill again, it kind of works like on the right. It's basically like, oh, I see where I've already downloaded those things, so no problem, I'll not download them again, but I'm going to compile them one at a time. It's, you can see that it's compiling the Ruby Bridge crate and the URL crate, which are basically the dependencies that I listed. And that's automatically, you don't have to do anything other than say that you're dependent on it. And then I'll just point out in the Rust code with RS, you can see on the top here, all I have to do is say, extra and create URL, extra and create Ruby Bridge. And that's all the code that you have to do to get cargo to do all to build it. So if you've ever written like, C or C++, that's like a billion times simpler to deal with dependencies. It's like writing in a minor program language. So now, I'm just going to do bundle exact, rack up, get the grU. I'm actually inside of a Ubuntu VM, so I have to minus O0, O0, O0, O0. So then, I'll be open from, I'm going to go to, okay. So you can see, it says, success incremented, Ubuntu.dev, I can go to like, ooh, like whatever, your own. Oh yes, so I flashed it on the screen, but it's very simple. You go back to the config.ru, you'll see it's, this was a benchmark. You can see that it basically doesn't do anything. It's a call. It basically says if you're before, then return 200 with the report that we get over the F5 and Rust. Otherwise, call the increfunction again over the F5 and say, success incremented. So you can see now that the actual work is done inside Ruby. It's just calling in the Rust through that little field. So I can say success. I can do like, oobar, awesome. And then if I go to .NET 2 slash report, you can see it'll give me a report and it basically, it's too big. So this is basically the default debug version of that structure. So actually if you go back and look at that structure, you'll see that I derived debug and derived debug basically says emit the code that is necessary to print the debugging version. And then if you look at the report, you'll see that the report is literally the same format that debugging code. And then send it back over as a debug, like a heap-allocated bug that you're planning to do. So, and this is basically just Ruby printing that same thing. I call two ads on it. So you can also see that it's definitely working as you can see. Baylight code that ICO is incrementing as I go. This is definitely, definitely real life. So I basically had a time here, but the key point here is not really anything about this specific example, but just to show that Rust beat produces a dinosaur file which you can load into Ruby. Ruby hasn't built in Fiddle. Rust is pretty good at supply. So without that much difficulty, you can take something that might be computationally intensive and convert it to Rust. And then call Ruby pretty easily using like normal tools that you're just using. Basically we look for correct. So I, both these examples, sorry. The example and also the livers that I use, which are very tiny, are on my GitHub. So github.com.com. It's like the last two reports in question. And I'm happy like anytime the next we base any questions inside of the program. Thanks. Thank you.