The Rust Memory Model for Beginners | Hatchpad Huddle with Damien Stanton

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
as i mentioned i'm damian my handle online is generally damien stanton or you can find me everywhere i already mentioned signal frame so what we do is we're an iot analytics startup and right now our focus is actually on helping enterprise customers build automatic contract contact tracing solutions during the covet pandemic but we also use our technology to do asset tracking and some other just general graph analytics so i call this i call this little chat really i don't think of it as much of a presentation or a talk as just a discussion um but i call it give and take because the unique thing about rest memory management system is the concept of ownership and borrowing and lifetimes and hopefully by the end of it you'll understand what all those words mean i don't have very many slides in the slide deck the bulk of what i want to do is to look at a chapter five of the tour of rust which is a really great website if you're familiar with golang you know the go tour is kind of the introduction to how most people learn the language uh as a real nice step-by-step procedural way to get the mental model in your head and torah rest really does the same thing for rest i'm just going to be looking at the chapter on ownership and borrowing because it really has a nice walk through of what these concepts are and as i'm going through and basically just reading along and looking at the code if you have any questions or you want me to try something out and say what would happen if you did this that'd be great because that's it's a nice way to kind of interactively look at it so just as a primer um we're probably all familiar with uh the stack and the heap in terms of the how processes manage memory um in case you're not uh the stack is generate generally a lasting first out data structure and it frames data data locally to um sort of the call tree of a given function so you define a function and you have some variables in it those values are assigned to the stack that is local to that function if the size can be known at compile time and this is different in different languages like i said this is a very high level overview i'm not going to get too much into the semantics or pedentics of any language in particular but just so you're aware of of these uh concepts uh is anyone not familiar with the stacking heap or what a pointer means when i say i have a value on the stack that points to something on the heap is everyone familiar with those concepts um can you give it a little bit of a brief brief primer uh sure sure so um so and this might make sense with the next couple of slides um but so basically um any program that you run needs a way to manage its memory um and there's typically uh sort of a quick fast access memory and a slower excess memory you can sort of think of an analogy to the way that a traditional computer might have a very fast um you know very fast high bandwidth ram uh random access memory and then you might have a comparatively slower ssd which is like your persistent storage it's loosely similar maybe um thinking about the stack and the heap so the stack because it's the location of the last thing on the stack is always known it's always the top thing it's much quicker to access and the stack has a known size so only elements that are smaller than a certain size will fit in the stack um whereas the heap is a little bit more complicated it's generally a bigger tree-like structure which is why the diagram looks like this and if you want to put something on the heap a lot of bookkeeping has to happen and the memory allocator you know program that acts as a part of your compiler needs to understand how to go find a space in the heap mark that as being for your particular piece of data that you want and then do all the shuffling to make sure that um you know there's no memory corruption so and what a pointer is in terms of this discussion of memory management is you have a value on the stack that references directly a value on the heap and so if in this example if c is if i have a pointer to c um i can reference the value of c in my particular function or whatever i'm doing to it but when i change the pointer to see that actually changes the value of c in the heap and we won't talk too much about the stack versus heap in rust it's actually kind of unique in that uh rust explicitly forces you to tell the compiler when you're putting something on the heap which is not really like other languages uh even c plus but um i think the only important distinction is just to know kind of what pointers are and what references are because that's uh that's sort of key to part of the ownership model and rust is that references sort of have some unique rules and um values have some unique uh kind of semantics around them uh that make it um that make it work the way that it does so does that make sense yeah that was great thank you sure and this is i love this this uh this gif uh this is kind of this is the canonical java example uh but when i say references versus values um so you can imagine say here that the cup might be a heap allocated object in memory when that when that object is changing if another place in your program has a reference to that uh those will sort of work in lockstep because it's actually referring to in the case of c plus for example it's referring to a specific address in memory um so so you can know that when you're referring to something you're actually like you're just looking at a pointer to another thing that's that's what these terms reference and pointer really mean they're just very direct um whereas in java for example when you pass something by a value you actually create a new object rus memory management system is unique in that uh when you do something like pass by value it's not in the animation but you can imagine that in rust the cup would actually be given to the fill cup function um it's called move semantics and we'll see that a little bit in the in the sort of walk through the tour uh but essentially um that's a key point is that uh rust enforces move semantics and it enforces the concept of ownership which we'll understand when we look at the look at the tour so just as kind to wrap up the primer um what it looks like in practice to actually use values and references i'll start with a java example because java doesn't allow access to pointers pointers do exist in java of course if you've written any non-trivial amount of java before you have definitely run into a null pointer exception error and that is because you've tried to access something typically that references some other object on the heap and maybe it wasn't initialized correctly or maybe it got muted in a way that you didn't know about or something but generally that that's one of the pitfalls of java is that when things are null or uninitialized or they you know you have a reference that you're not really aware of because you don't have access to pointers you might run into problems and comparatively when you look at go which is sort of maybe a next step down the ladder towards manual memory management you do have access to pointers so there's a semantic difference between when i'm passing in here a person versus when i'm passing in a pointer to person here for example i know that i'm explicitly allocating because i'm passing in a pointer to something that exists on peep and then if we look at c plus it's more or less the same thing as go when we look at the tour i'll talk a little bit about move semantics in c plus plus i think a lot of the current standards in c plus plus have been updated to reflect some of the same ideas that you might see in rust but as someone else mentioned rust has a very powerful type system and it's uh it's a little bit different so the concepts of like move semantics and resource acquisition is initialization which you'll see that acronym here i'll talk really briefly about that those concepts are pretty well tied together um and this is all just to say that uh the memory management system in rust even though it's very unlike c plus plus that's probably where it's uh most closely related as opposed to like go or java or python or something like that another language ecosystem that is somewhat similar it might be swift if you do any ios development swift does allow you to access raw pointers um but it also has a distinction about whether values uh exist or not uh its memory management system is different it is garbage collected so i won't speak about that but that is just something to keep in mind is that you don't want to be thinking about sort of a garbage collected system that does all the work for you the rest is a little bit closer to c plus plus in terms of you have to think about the lifetimes and scopes of things and how long something exists for which you'll understand when we look at the tour um so it's it's uh like i said it's a third path it's not exactly uh manual memory management but it's also not garbage collected and we'll see how that works as we go through the tour so let's see do you all see the tour of rust and there's the crab here yeah yeah it looks good great okay um and how's the text size i don't know if if this is uh too small or should i make it larger you could expand it a little bit maybe sure how's that looks looks good okay great so uh so this key concept the first thing what is ownership so um this is it's kind of it's a tautological almost they say okay well instantiating a type and binding to a variable creates a memory resource and the bound variable is called the resources owner okay so foo is the owner of this data structure we don't really know what that means yet but it'll make sense as we go along but that's the first thing to say so when we create a data structure it's bound to a variable that variable owns that piece of data in memory and so what resource acquisition is initialization is and this is a concept that was sort of pushed forward into c plus loss community because people would constantly if you've ever written c plus plus you've probably run into segmentation fault issues or you've had a problem such as a dangling pointer which is where so we talked about having a value in the stack that points to something on the heap you could very well imagine that in a c plus function you could reference a value that's on the heap do some operation that fails and then that function returns before that pointer was able to be deallocated um well more correctly to say before that pointer is able to be destroyed or dropped this concept from dropping um and this can actually lead to really severe security vulnerabilities um i can't remember the cd number but there was a very well-known uh memory bug in internet explorer version 6 all the way through 11 that was caused basically because of a dangling pointer where a pointer to a place in memory was not properly cleaned up uh because it in siebel's plessy it's it's manual um this is not properly cleaned up and that pointer pointed to an address in memory that later on an attacker was able to just say hey there's a pointer here that goes to a place in memory what happens if i access read that memory maybe i can figure out how to execute code there so it's a real issue um and uh this concept of rai basically says okay well if we can build uh classes and functions and data structures that explicitly describe sort of the scope of how long something is supposed to exist for then we know that it's going to be dropped and there's some examples in uh sort of the canonical c plus um reference website is cvpreference.com if you look there on this topic of rai the example they give is like a um a mutex so if you've ever uh written c or go you know that a mutex is used to sort of say i want to lock access to like say i have a bunch of threads who are looking at a piece of data i want to lock access to it the example they give in this rai tutorial is to say well if you do it manually and you say lock and then do something you might accidentally return the function or go do something else before the lock is released and then that's that's a dangling pointer so rai basically says well if you use a different function that has like a safe like safe mutex that will always drop any anything that it's locking it'll always release the lock as soon as it goes out of scope then that can't happen and it sort of obviates that issue um now in c plus plus uh these this is all done by hand so you have to use a particular class or use a particular function or method that is sort of designed by the programmer to to implement and enforce our aii and that's why people say that it's a programming paradigm or you know style it's not really a it's not something that's enforceable other than by maybe a very smart compiler or just programming practices so uh one thing that russ does is that it enforces our ai um when things go out of scope they're always dropped and this dropping is hierarchical so what that means is that here in this example is pretty self-explanatory when you have a data structure that contains another data structure when that first one goes out of scope it gets uh it gets dropped first and then its sort of interior piece of data gets dropped and there's sort of a drop like a in c plus these would be destructor calls uh the sort of a chain of dropping um and these resources can only be dropped once and this is important because another uh sort of classic c memory management issue that programmers run into is say you um say if you're using this plain c and you create a piece of data you allocate the memory using malloc function you do the right thing you free the memory when you're done but then you forget that you freed it and then you try to free it again later that's also an error so this is another thing that the rest compiler does uh to enforce this idea is that uh when things are destructed that can only happen once and you can actually you can write a lot of this sort of scope-managed um dropping of memory that's gone out of scope is done automatically and the implementations are actually uh the compiler is smart enough to be able to understand how to implement uh drop for like for example foo and bar because this is just the primitive type it's very simple but if you had a really complex type um you could implement drop yourself just like you would in c plus plus with a destructor you could just say okay well when i want the um when i want to release the memory here's how i want it to happen okay so here is what i meant when i talked about move semantics so if you think about the coffee cup analogy rather than so in that uh in that c plus plus example if i uh pass in a particular instance of a class say um that value actually gets copied so that in simple suppose you'd say that's copy constructor gets called um the same thing occurs in java you you uh when you pass a piece of data by value the whole piece of data gets copied now in rust that's not the case when you pass the data around in rust unless you're passing a reference and will understand what references are in a bit the data is explicitly moved so the ownership transfers from place a to place b so this is uh best understood in the code so say we have this foo object here we pass it in to do something and do something just print it but what happens is in the main call stack when we pass something to foo if we tried to use foo after this it would not work you would get a value cannot be used after move error by the compiler and it would actually it's smart enough to tell you okay well the data moved here and uh this isn't uh it doesn't impact you so much when you're looking at something extremely trivial like this but it's very important when you talk about multi-threaded programming and rust or you talk about async and doing computations that use sort of higher level abstractions than threads directly it's very important because data tracking the movement of data is a key to how the memory management system works and as i mentioned here so when the owner's value is copied to the function called parameter stack memory so if i have a function here that returns a value and i pass it to another thing if i'm not passing a reference and i'm passing the real foo then that data actually moves so it's an important thing to understand now in c plus plus there is a function to do this it's called standard move and you call move on an object and you can actually tell it to do this um in rust this is a part of the way the compiler works so um again it's it's sort of it's the same idea where in c plus plus you would have to sort of opt in to do this whereas in rust it's a part of the compiler it's a part of the syntax of the language damien i'm going to jump in here it looks like we've got a couple of questions in the chat box do you want to just go ahead and actually ask her is that easier yeah so unfortunately i can't see the chat right now oh yeah no worries that's why i figured as you're good transitioning yeah just not me any time anytime like if something doesn't make sense please just shout out and say hey wait what is that uh okay i don't want to go too fast do you want to bug you um so i think you were saying like before uh that data is dropped once it gets out of scope so is writing the code in scope kind of like wrapping up it's kind of like a wrapper around like uh memory alloc and deallocation actions yes it's very similar so um and then scoping in rest uh works by way of the actual it's actually part of the lexing in the the language parser so if if you put something in curly brackets for example uh this is an explicit scope so if i tried to um if i tried to access like say i defined 10 different variables in here inside this particular block if i tried to access those out here they wouldn't be valid anymore so it is it is like um it is sort of like a a language-enforced version of um of doing that memory management explicitly yeah the second question i had was um so for russ you said that you can only drop things once does it throw an error on dropping or does it just light the air and say you can't you mean if uh if something went wrong during the drop um if you're dropping it twice uh was the thing i was imagining oh no so um [Music] so you you it would be a compiler error you would get you would it would say that you couldn't like value has already been uh i don't know what the exact error message is it's not value has already been dropped but you wouldn't be able to do that it would be a compile time error it's a move error because the drop trade takes ownership of anything it's implemented on so if you try to drop it a second time like you called standard mem drop to manually drop it that um yeah that's the error you would see yeah so it's compiled on that runtime cool thanks okay okay so now to talk about references um so this is a point of contention sometimes with uh go or c plus programmers because the syntax for references looks like the syntax for pointers in other languages rust does have raw pointers but generally in rust all of the pointer semantics uh work around what are called smart pointers uh in c bless plus those are those are um just like with move and with other operations that sort of enforce this rai thing those are specific functions so you call make a unique pointer or make a shared pointer or things like that and rest this is baked into the language so references um like it says here you can borrow access to a resource and references are dropped just like just like other other things [Music] i like that they phrase it this way to say references allow us to borrow access um this is important because it's it's sort of like saying you can't if you're not moving ownership if you're not taking something and becoming its owner you can't you can't take it you can't have it you have to borrow it but then at some point you you don't have ownership of that piece of data anymore so you just borrow that's what why it's called borrowing you just have the reference for to this thing for a particular lifetime and there are a couple sections on lifetimes later um so that's like kind of kind of the three the three things that hold up the rest memory management system are um the concept of ownership so how data moves around in terms of move semantics references for how like when you reference something how does the compiler understand how long that reference should be valid for it's an interesting question that comes up a lot in multi-threaded and concurrent programming and then the third piece is okay so when i say you you have ownership you have references to it and then okay so how long does that does the borrow how long does that reference live for was that uh for for smart references or smart pointers do you have only like certain limited permissions on what you can do with that data like is it only read-only or do you also have the ability to write that that is a great question uh you basically have asked the question that is answered by this next slide which is um so rust a little bit like swift other other languages where you have to define the mutability of an object explicitly when you declare it so like if i if this if foo was not mute i could not take a mutable reference to it and i also wouldn't be able to change food later so like if i tried to say foo dot x is 99 that would be a compile error because foo is not declared as mutable so in rest you have to declare any time a value is able to be changed and likewise when you take a reference to a mutable thing uh that that holds true there as well so you have to assign you have to tell the compiler explicitly whenever data is mutable so i don't know if that answers that question directly but yes so it's kind of like constant or var val kind of syntax exactly yeah so instead of like let is always immutable let mute is mutable cool sure yep yeah and this is interesting this is interesting piece of code to kind of step through so do something prints the value here but do something takes a foo it does not take a reference to foo so do something consumes the value it takes ownership of it so if you do so you gave out safu exists you kind of have it up here in space you created f which is immutable reference to foo so now anybody who wants to do something with f that reference will point back to foo on the heap if you tried to pass the original object foo to something else that's a compile time error because the compiler isn't going to let you move a piece of data that has a mutable reference to it out there somewhere and this is super helpful when you have uh you know potentially like you're doing multi-threaded programming and you may be having like a wide dispersal of references to a particular data type you don't want to allow that piece of data to move around in unexpected ways what i just said doesn't doesn't really work semantically because there's uh the way that references work as far as multi-threading they're not allowed to be shared they're like there are special types of rust called um interior types that allow interior mutability but that's that's kind of getting getting way ahead and it's not really useful for for this discussion um but just to suffice to say that uh it's really really helpful to have the uh to have a difference between a reference and potentially mutable reference to an object and the actual object and to know when those can change and move so going back to the example so do something foo is a compiler error because you can't you can't move a piece of data when a mutable reference to it exists um and also trying to modify it here even though the piece of data was declared is mutable because you have immutable reference to it the compiler wouldn't be able to know okay well which how does it know which which uh sort of which caller if you will is is the correct one to change the piece of data it doesn't work so even though foo is mutable here because you gave out a reference to it um it can't be modified uh directly anymore so then say okay you do the right thing you go through the mutable reference which is the safe way to access that piece of data and access its memory you you modify it now the compiler knows for the rest of this scope you're not using f anymore so f is dropped so now it's now it's gone now immutable reference to foo no longer exists so now foo is free to be mutated again so that's kind of the crux of how this memory management system works at the most basic level um in in c plus plus the function that creates the equivalent of um of rust rest reference is called unique pointer and i love that that function name because that's exactly what it is it's a unique reference that is handed out and when you hand it out you can't change the original piece of data except through that reference so until that reference goes out of scope the the original piece of data even if it's mutable is no longer accessible and and because you can do that at scale with all the different variables in your program that's how the memory management system is able to work without a garbage collector um the only piece that's sort of missing from how that works is lifetimes which we'll get into in a bit wait so you can't hand out arbitrary references to immutable data you uh i'm not sure about so you can't you can't hand out mute arbitrary mutable uh you can't hand out arbitrary references to immutable data like for for mutable i understand like handing out arbitrary references would uh since you might be able to mutate that data underneath like it might result in in memory safety issues but for immutable data um i guess no no you can you can handle reference when i was talking about uh handing out one explicit reference i just meant the mutable reference oh okay yeah and typically and you'll see this in in if you look at russ codebases you'll see um often uh functions will take a reference to a particular type rather than take ownership of the type um but you can have multiple references to an immutable piece of data cool i have a question so um you're assigning 13 to x and uh foo if you wanted to do uh more to it you could it just drops it because it knows that there's nothing else in that scope that tries to modify it yeah so let's see here so if we run this with 13 and 7 so yeah and then what if you move that line to line 28 would you get the error um on the on line 27. uh so here so yep okay yeah and one one thing that's very helpful with rust compared to c plus or other other languages is that the compiler is very um is very explicit about what's happening even if the language in the compilation error is is like confusing um it'll generally tell you what's happening um and when we look at lifetimes uh i don't know if i i don't think we'll have time to figure out something that triggers a compiled time error for lifetimes but um it gets very very specific like it'll say you declared something that had this lifetime which doesn't live long enough for this but it does apply to this and it's very helpful so i often joke that like writing risk programs is really just getting into a debate with the compiler and then once it agrees that you've written something that won't you know crash or cause a memory issue then it's fine does um for for foo because foo is it looks like a struct uh source is the is the mutability or is immutability referring to like just a structure as a struct plus values oh that's the struct plus value so this so this is so foo here is uh so this so rust has um struck literals just like go so this is an inst this is an instance of boo like you've created a foo here and you're marking that this this data structure is mutable here um if it was immutable though um and you were modifying would you be able to modify the value within the struct um within it well i mean you mean during initialization or uh after initialization no so so if you if like if this was not mutable um let's see this will compile so you get this error can it assign to fx just line behind uh a shared reference okay well sorry it should say exclusive reference okay i know that's the thing in python so yeah all right and this part's not that interesting um just like with other languages you have a different dereference operator so you can de-reference um values that have like if you if you have a shared reference you can de-reference it to sort of get their value and modify it but that's just a syntactical thing okay so the last piece of this and i'm running out of time uh the third thing that makes the rest system work without a garbage collector is lifetimes um so uh the key point here um so you can have and we actually solve this compiler error so you can only have one mutable reference out at a time you can have multiple immutable references you can't have both we saw that compiler error and this is key reference must never live longer than its owner um so a lifetime just generically whether you're talking about rust or sibling plus or whatever a lifetime is basically the lifetime of an object in memory starts when it comes into scope and it ends when it goes out of scope so the data is alive in the scope and not outside of it so this is just explaining why this is a useful concept i'm going to skip over so there's this piece here you can use references of references which is not that's this just gets confusing um but it is useful in some cases but it's not important for this so the last piece i want to talk about is explicit lifetimes so like i said a lifetime corresponds to um when something comes into scope versus when it goes out of scope uh the rust compiler generally um infers and elides lifetimes so that's why we haven't seen the syntax before now um the a way that i've heard lifetimes described that i really like is if you think about generics in java for example or c plus plus you know that you can provide sort of annotations to describe some type that doesn't exist uh concretely but is sort of an abstract type so you can say if i want to log anything no matter the type i can say that the say in c plus plus you'd say the template type is t or in java you'd say the generic type is t lifetimes in rust are sort of like generics they're like generic types but instead of corresponding to the shape of data they refer to how long a scope is so you can say so this lifetime annotation tick a is basically saying do something generically over something that exists for at least as long as a and so when you understand it that way and if you think about it in terms of something like a generic it becomes much easier to understand what's happening so you can say do something can only operate on data that lives for at least as long as a so i take in a reference to foo which lives for that long and i return an integer value that also lives that long and so when you look in the code it's the same way um you can you can do something with the reference and then it gets dropped later but the lifetime annotation here is just to say uh whatever this piece of data foo is it has to live for this long and what what this is is just arbitrary the um like the the standard practice is to use these single letters but i think sometimes it's more useful to say like maybe would be better even though it ends up getting really noisy this way it's sort of more semantically explicit because i'm saying do something operates on things that live at least as long as foo and then foo has to live that same length the reference for this can't be dropped before whatever this means this lifetime foo has passed um so when you look at russ code it's it's best to think of this in terms of like maybe you call it like a temporal generic like it's a generic uh it's a generic type over the scope of something rather than like the data type if that makes sense um so um what is explicit is our explicit lifetimes only used for single threaded code or can you also use it for for multi-threading when you don't know when something may be or not be in scope uh yes you you would use it so you would use it um and actually i think there's they don't go through multi-threading but there are some examples of using lifetimes in data types directly um so that's where where the impact would come in um but it does it does apply to uh to multi-threaded uh or async code as well and this is just uh this is just sort of an extension of that where um this doesn't really mean anything different it's just saying that you can have um you can have multiple lifetimes in a particular function or a piece of data and they don't have to correspond to each other necessarily so we take a foo in here that lives for this long and we're returning an integer that lives this long we don't care if uh foo a gets dropped because we only explicitly told the compiler i need you to guarantee that while the function has to live for this long of course it does because otherwise you wouldn't be able to have a receiver of this type of data but the return value just has to live as long as this so i don't care if you clean up tick a foo here um a third another piece to the lifetime um sort of methodology is static and this is this is much simpler i think than than you would think static just means uh what you would expect the reference for it lives for the life of the program um string literals in rust so if you just say let boo equal damian as the string string wrap string literals in rust are static references to this stereotype uh i definitely don't have time to go into the difference between references to stir and the string capital s type in rest they are they're actually different types and that is a huge source of confusion but it's beyond the scope of this talk but essentially this is just to say that you can define that a reference to something must be static and i would also ignore the unsafe part here for now i've heard things about unsafe how prevalent is it within dependencies and how how does that impact the the need to like validate your dependency chain um i would say most so i don't know it depends on what it depends on what dependency you're installing um if it is something that is heavily optimized or that has to do any sort of manual memory reclamation or you know working with raw pointers for example like say uh if you're using um i'm trying to think of an example uh you know if you're doing c ffi for example uh rest has a pretty strong foreign function interface component to it that lets you interface with c um and all c code is unsafe for example so if you're using a rust wrapper around a c library there's of course going to be some unsafe code there um because you can't like once you throw the data over the wall to the to the or pull data from the c side of things you don't really have any guarantees about it um but generally i mean from what i've seen uh you know i haven't gone line by line through a lot of the dependencies that i tend to use but unsafe is not um it's not that prevalent unless for performance reasons um but there's a sort of there's a misconception about the key word i think they probably could have chosen a different word but when you declare something in an unsafe block um what you're saying is not necessarily that it's not memory safe but you're saying that you don't like how do i say it you're saying that you have guaranteed that it's memory safe so you're telling the compiler don't memory say don't do everything that you do to check this for memory safety i'm telling you that it's safe so it's it's a bit of an unfortunate keyword but really it just means uh i know what i'm doing uh allow you know allow raw pointers allow manual memory management in this space it's really what it means but if you get a runtime error then it's not memory safe right in order to just allow right uh well that is something that can happen so you it's and that's the reason that they chose unsafe even though it's a little bit inverse of what you're actually doing is you're saying that you're guaranteeing that it's memory safe that that is the the trade-off is that if if you write something in an unsafe block you could do things that would cause the equivalent of a segmentation fault or other problems um but generally it's i mean it's the practice in the community to not write unsafe um unless you really have to like there has to be a good technical trade-off for why you would want to write something in your own safe code but i would say it's not that prevalent generally i'm gonna jump in here as well i know we're getting close to the end of our time but were there any last one or two questions that anybody wants to bring up yeah that was really it uh from my side as well lifetimes were the last thing awesome so how would you rate the maturity of the the rust ecosystem and tool chain right now and um do you see like significant improvements or changes like on the horizon yeah so um so rust is very stable now uh i was actually chatting with a couple of my friends the other day uh 1.0 came out in may 2015. um it's been out for for a while uh the one place where rust is definitely still having a lot of api fluctuation um is around async await so we didn't talk about multi-threading really at all but basically um there are data types in rust uh there's a standard in the standard library there are futures um and just like it's it's akin to the model that you see in typescript or javascript uh or python where you have async basic you declare functions as async and then you can await await values on those functions um and there are what's sort of not standardized now around that is like how should the the task execution model work for that um and should it be uh should it be an external library external crate or should it be built into the standard library so some of the stuff around features and async are changing still that's that's by design actually um the core language team i can try to find it and send it out to folks afterwards wrote up a pretty good blog post on that design decision to not couple async await to a specific runtime or approach and they have some good use cases and some good examples of how that's allowed the ecosystem to build or adopt different run times based on you know what kind of application you're building you know cli versus a web service versus embedded coding or something like that at a high level so it's not it's not that it's unsettled per se that that that was a core team deliberate choice i would say at this point uh tokyo is far and away from most general use cases i think uh pretty widely adopted as a general run time uh and maybe where it's less settled is in some of these other use cases um there may be still work ongoing that to produce run times that are more suitable like again the embedded working group is pretty active and you can imagine in a resource constrained environment you might not take the same approach implementing your run time there as you would on you know a more general purpose system yeah that's a great point yeah i i had a point uh that i thought of when someone was talking about the unsafe block uh about a year and a half ago i did a talk on reverse engineering and uh when i was making uh some examples like calling c apis that's when i was actually using the unsafe uh keyword and and i believe other languages like node.js and stuff they use the foreign function interface ffi but with rust i was noticing that if you're use if you're calling c apis or you're calling other types of languages using unsafe becomes more useful um but i just wanted to add that tidbit can you wrap unsafe ffi data in uh in a safe manner like you cast it to rust types uh i don't know that's a good question um i'd have to look that up i don't think you can i'm not sure i'd have to look that up cool um i did have one last question if nobody else had anything i think i have a lot of questions so if anybody else had questions um i heard really great things about rust type system um so i think i studied haskell for three months uh earlier this year um and you know they have like higher kind of types of things somebody mentioned the chat thomas i think you mentioned uh like lifetimes are kind of like higher kind of types um there's also you know like options uh either i think um yeah error handling or rust is heavily inspired by haskell and other functional languages so rather than having a null outside of uh unsafe blocks yeah you're dealing with tri types and option types and they're they're straight up monads so if you understand that concept then you're not going to have any trouble with air cramping and rust are there other features of the rust type system that that particularly stand out so one thing one thing that i think is really powerful um it does have a very good and somewhat hygienic macro system which is useful for sort of having um variatic functions that work on different types of data and then there's something called procedural macros which sort of let you really extend the language almost and operate on token streams of rust code which is really cool but one thing that i think is really really powerful in rust is the trait system the trade system is heavily inspired by haskell type classes and what it lets you do is if you think of a java interface or a go interface you're describing the behavior of a particular type without describing its shape or its features in rust you can do this as well but you can very explicitly bound amongst different traits and you can combine them and you can say that a particular function for example or sorry a particular data type is only able to be used in this particular function if it matches all these traits and they have and those data types have these other traits and it's super super useful because you can basically just tell the compiler exactly how a piece of data sort of move your program flow and you'll be explicitly describing its behavior in such a way that it can't operate like it's it's not possible for it to operate in any other manner so the trait system is super super helpful for writing correct code i found so you have things like orderable and innumerable and like things like like innumerable inherits from orderable and stuff like that yeah exactly and it's really powerful because you can define custom traits that allow you to transform type a to type b in a in a type and memory safe manner and it just it just ends up being really helpful so you sort of take all these things into one umbrella and you say okay well the the scoping is really enforced the type system is really enforced and the behaviors on those types are also really enforced the sort of net effect is even though it's a different mental model um i've like once you write it's a little bit like haskell like once you write a piece of code that correctly compiles and runs you can be super super sure that you're not going to get runtime errors like of course you know leaving data validation outside the scope of it but it's it's really helpful for writing correct code um and that's and in the sort of experiments that i've done at work with it it's saved me a ton of time especially when it's like a project that i'm working on myself that has to run at a particular scale it's just really helpful to be able to organize the program that way
Info
Channel: hatchpad
Views: 2,209
Rating: undefined out of 5
Keywords:
Id: zO1a2986NHg
Channel Id: undefined
Length: 50min 32sec (3032 seconds)
Published: Mon Sep 28 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.