 Hello. Can you hear me? It's fine. I'm going to talk about REST memory management. A bit about myself. My name is Ishaan Ali. I work for a company called Kinfolk. You might be hearing this name quite a lot in this conference. A bit about REST before I get into the memory management, because if you don't know anything about REST and I get into memory management, it won't be very useful. But I'm not going to go on about all the features and everything. I don't need to mention those. Mainly, it's a systems programming language like C, C++, Go in those categories. But it's one of the first languages to ever focus on safety and efficiency at the same time. There you will find many languages that are extremely safe, especially all those functional programming languages. But they will always have some performance penalties in terms of, for example, garbage collector at least. No matter how efficient you make garbage collector, there is always going to be some performance penalty of that. So REST aims to not have a garbage collector and may have things as efficient as possible. Very similar to C and C++ in that way that you do have to think about memory, but not as much and there's no dangling pointers that you have to free and you forget. Then there's a problem there. It builds on something they call zero cost abstractions. So any API that you will use in REST, for example, the iterators or something like that, they don't cost you more than they would in any other language that is also efficient like C and C++. So that is at the cornerstone of the language design. Everything goes on the stack by default unless you don't want it to and then you have an API to do that. I'll talk about that later. Non-mutable state by default. So every variable is non-mutable. Once you assign it something, that binding is permanent. You can't change it after that, except if you mark it as mutable. And that makes things really easy when you have to find out some problem that's happening. Your problem is going to be always in the mutable states. And if it's clearly marked, which part of your code, which variables are mutable, it becomes much easier to track down problems. It has strict ownership semantics. So as I said, not like in C and C++, you don't have to free things. But it has very strict rules about who owns a particular resource. And I will show you in the code what I mean by this. Enems can have values. I had to mention this because I'll show you a code where we make use of this. So I thought I should mention that. And it's even more complicated than this. It's not just that it has values, but it can be like a struct. Like as you can see the move part, you have like variables in there. So and sorry, Rust has traits to allow polymorphism in the language. Rust is not strictly object-oriented language if you come from other languages that are object-oriented. So you don't have classes in there. But you have similar concepts. And you have structs, you have traits. And through that you implement, you have a concept of polymorphism. Also, Rust makes use of traits quite a lot. So all capabilities are usually implemented through the use of traits. And that's why one of the reasons I had to mention this. And as you can see, it's pretty simple. You create a struct, you have a struct, you define it. Then you can define traits on it and implement the traits. And so that was a very quick intro to Rust language. There's a lot more to Rust than what I said. But it gives you some overview at least. Now I'll dive a bit into memory management. I'll start with just giving you code samples and then showing you what is wrong with them and how we can correct it. So this one, if in any other languages you had this code, you would assume this is completely correct and that they should just compile. So there's a function call at first two and it takes a vector. You can call it an array of integers and it just adds first two elements and return the value. And main function is nothing doing nothing fancy. It's using a macro to create a vector easily. And it just uses that first two and then shows you the results. The problem is it's showing you the results afterwards in the print function. The rest will give you an error. It says that the value moved here and then you can't use the value after you have moved it. This is what I was talking about earlier about these strict ownership semantics. So if you pass something by value, there's two things to keep in mind. It depends on what kind of type it is that you are passing. If it's a copy type, which is usually all the basic types like integers, floating part numbers, Booleans, all those, they're always copy types. And they're copy types because there's a trait called copy which is implemented on them. And if that type, then when you pass them to a function, they're always copied implicitly for you. And that's because there is no performance penalty for that. It's very simple. And the other function gets a copy of it. And it keeps its copy and you have your copy. And then that function returns. It just frees its own copy. And the calling function already had its copy. So it will automatically be freed. But there is something called move semantics in Rust. And by move, I don't mean moving the resource itself. Nothing is actually getting moved. The only thing that gets moved is the ownership of the resource. So most types are of this type, move type. So when you pass to a function, you actually pass the ownership of that resource to that function. And many times, that's not what you want. You don't want to give your ownership of your resources to the calling function. You just want to do something and it returns. And of course, Rust allows that through a concept called borrowing, which is very similar to pass by reference in C and C++. Mostly, you call it that in C++, not in C. You don't usually say by reference. But by that, you mean like you pass a pointer in the C lingo. And the function doesn't get ownership. So you borrow the ownership to the resource to the function. And when the function returns, the borrow is you have the ownership back to you. And that's how most APIs you will find in Rust because nobody wants to have APIs which takes ownership of the resources. Of course, there is a lot that all do take the ownership, but it's very explicitly mentioned in the documentation why it's the case. The problem with borrowing is that it's very temporary. So for example, in this code, there's a struct that represents a helicopter, and there's a registration sign for it. And you have a constructor for this struct, a new method. It could be named anything, as far as I know. But we call it name. There's a syntax error here, probably when I was editing the slides, I made a mistake. But that's hally from the new is a return type. There's a dash missing at the return type. Anyway, so this takes a registration and it wants to keep it. And so once it takes that registration that belongs to the constructor and the constructor is giving the ownership to the struct, so you don't have the ownership anymore in the main function. Once you call the hally, call and call on you. And you are using it again. So just like last time, you will get an error because you moved the value and now you're using it yourself again. And you can't do that because you gave the ownership away. And as you can see, you get a helpful note that why this is so. So the string type we have is not implementing the copy trait. So Rust cannot implicitly assume that you want to copy this resource. And it shouldn't be because strings are heavy. So we come to something called RC, which is the type that represents reference counting. And basically, it's a container type. So you put things in it of different types since it's a generic type. So you can put arbitrary types into it. And I'll just quickly go back to the previous code. In here, we couldn't have used referencing because, as I said, referencing or borrowing is temporary. So the constructor couldn't have put borrowed value into this struct. It couldn't have taken ownership of something it doesn't own. It's only borrowing it. So that's why we can't use borrowing here. So we need to use reference counted object. Sorry. So you can only borrow it. What enforces this? What keeps it from the Heli mission from around forever? If you look at in this code, right? So in main, you have the Heli assignment, the variable. So when it goes out of scope, it will be freed automatically. The struct. And once the struct goes out of scope, then the resources it owns will also go out of scope. And I was about to explain that in the reference counting, the RC, you can have multiple instances of the same resource because there is different instances of RC. But the underlying resource, it's shared between them. So when you call the Heli new, and then you cloned the registration, you created a new instance of the RC struct that you cloned the existing one. So now there is two. One went to the Heli constructor that it kept. And the other clone that you already had in the main, it remained assigned to the reg. But the underlying resource, which is the string there, it remained shared between them. So each time you clone it, the reference count on the underlying resource increases. And when it goes out of scope, the binding, it automatically frees that instance. And decreases the reference count on the resource that is being shared. And once it goes to zero, the actual resource gets freed as well. Yeah? Yeah. So there's things keeping ownership of other things. So the Heli struct is keeping ownership of the registration. But as you see, in here, we had to write RC string. RC string everywhere, you can make it better by using a feature of Rust called type aliasing. So you just defined RCS, and you make it like RC string. From the point of view of compiler, now they are the same exact type. It will automatically replace the all usage of RCS by RC string in your code. And it will work like as if it's that type. For this particular RC string, there's only one thing being contained. So it's a simple type, so it's not very useful. But we will see in a later example that it quickly becomes useful. But the problem with RC is that it's not thread safe. It's made to be efficient. So if you want to share resources between different parts of the code and you don't have multiple threads, then you can use RC and you should use RC. But like, for example, this code, we are now, it's the same code, but we're now adding, threading to it. And I had to add one more method to demonstrate how it will affect things. So now it has a hover method, and it just shows the self-drag, the registration. Now there's nothing fancy. And in the main, you just launch a new thread. And in that one, you call the hover. And if you run this code, you will get errors from compiler again. Basically what this error means is that you cannot share RC between threads. There is a trait that needs to be implemented by types that can be safely shared between threads. And that is not very lightweight. So there is a cost to it. And that's why we have a different one called atomic reference counting, which is the same as RC, but it's thread safe and it's a bit heavier. You can use it in single-threaded as well case, but since it's more heavy, there is no point of using it in that instance. It's kind of the same code, except that I replace RC with ARC, and this one just works. Sorry. And I think it's quite the same, so I don't know if I need to explain further. But the problem is that ARC content are not mutable. It's only about atomic reference counting and the resource. And if you look at that, like the self dot reg, when you use that, you borrow the contained value. And when you borrow it, it's not a mutable borrow. It's a non-mutable one. So if you want to have a mutable resource, like in this one, I changed the hover method to do some writing and clearing of the string. Like I introduced a new string, the stamp status. And this won't work, because as I said, when you borrow from ARC, the internal value, it's not mutable. So you can't do mutable. You can't call methods that assume a mutable reference. So this won't work. So you have another type for that, mutics. And as I was saying, type aliasing, we can use it now in this one. But for the sake of demonstration, I didn't use it to keep it simple. You basically just put it mutics in an ARC and then the mutics itself, you just take a lock on it. And that lock is an object itself. So when you get that, as you can see, I'm then taking the actual resource by calling unwrap on it. Don't worry about unwrap right now. But anyway, you get a mutable reference. And once you get a lock on it, and then you can do all the mutable, you can call all the methods that require a mutable reference. And it works fine. And the thing about these locks is that when they go out of scope, they will automatically be freed, and that free means unlocking. So when the hover function is done method, you get the unlocking automatically. So you don't need to explicitly unlock mutixes. Otherwise, it's pretty similar to just using ARC. Similar to mutics, there is a read write lock as well. So if you have multiple threads reading and multiple threads and a few threads writing, so if you have a lot of reading going on and very few writes at the same time, then you want to use this one because it's a lot more efficient. There's a think-all box. Like I said, I mentioned before, everything goes on the stack. But if you want, you can put things on the heap. And this box is the way to do that. So this five in here is not the size of the box. It's just an integer. So it's just the contained value. It's a generic type. So you can pass it Boolean or any type. And it keeps it in the box. The box itself is still on the stack. But the resource that you put in there, that goes on the heap. This box is used a lot for scene interfacing, where you need to pass arbitrary memory areas from the heap to the sea world. But there is also another use of it, and that's for sizing. So many times, the compiler needs to know the size of the types. And let's see an example. For example, in this case, so you have an enum that is lists, but it can be a list itself as a member in it. So the compiler doesn't know how large could it be because lists can have a list and a list and a list. So for that reason, you can use a box. But the compiler knows exactly how many bytes a box takes. The list is just something it holds inside it on the heap. So the compiler doesn't need to care about that. And it knows exactly what size this type would need. So yeah, this will work. That's like a very quick intro to Rust memory management. The main rationale for this talk is that when people start with Rust, they really have to fight a lot with the compiler. But once they're done fighting with the compiler, the result is just magical because once your code compiles, usually everything just works and the debugging almost completely goes away. Unless you use a lot of those unwrapped calls that I didn't explain. And I don't want to explain right now and have time. So you have one minute for the, three minutes. Any questions? Does Rust have something like in C++ where you have allocators where you can specify how the memory is allocated for your types? So you can have like, if you allocate lots of stuff, so you can be sure that it's in a contiguous piece of memory? So when you do like a box of something, can you as a user specify where in the memory that will go or it's just the TC malloc or J malloc order is to take care of everything? Not with the box, but there is APIs to handle pointers. And that says unsafe code. So you have to market as unsafe when you use those APIs. But you can do like, you can create a pointer that points to a specific part of memory and you can do all kinds of things with that. But of course, then you are an unsafe world. But you do have to use those APIs quite a bit if you're interfacing with C because you need to do those things, pointers and stuff. But usually in when you are doing safe risk code and not interfacing with C, you don't have to usually care about pointers at all. Any other? No? Then I must have done a good job or something. Okay. So thanks for coming and have a nice evening.