Fear Not the Big Bad Borrow Checker

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right welcome everybody hello we are here for another rust stream on the microsoft developer twitch channel i'm very excited to be here um i yesterday i was on the stream we talked a little bit about rust and then later on in the day some colleagues of mine were on to talk more about rust specifically what it's good for what what you might use it for various things about how to learn rust and things like that and today what we're going to be doing is tackling the question of the borrow checker the borrow checker is in some ways the thing that makes rust really special uh and so we are going to uh be looking at that examining it we have about an hour maybe a little bit more uh this this evening this morning this afternoon wherever you happen to be uh to look at the borrow checker um and uh really to explore it and to to get a better understanding now an hour after an hour we probably won't have a deep deep deep understanding of what the borrow checker is all about but hopefully if you've done any rust programming before this will be a good way to kind of ask the questions that might be you might be struggling with to to get a better feel of of what's going on with that being said i'm going to switch on over here to this view here and just a reminder that we are talking about rust of course um so if you want to learn more about the language you can find the main page right here where you can find a lot of different information about rust including um very importantly if you've not done so rustup.rs which is a tool for installing the rust tool chain and core tooling that goes with it so if you've not done so make sure to to go ahead and visit restup.rs here and if you're looking for the recommended way for writing rust i personally would recommend vs code along with the rust analyzer extension uh which is a really great extension and will soon i believe be the official extension for uh for rust so check that out and if you have any questions about that uh let me know um chat i would really love to know what experience you have with rust and how how much rust you've done before whether that's absolutely zero all the way up to you've been writing it since uh 0.1 and you're in the inventor of the language would really like to know what that uh what experience you do have with the language um so that we can get a good feel of of who we have here in the stream as well as what type of uh different questions you might have when it comes to the borrow checker all right so um i'm going to switch over to terminal here i'm running a wsl on windows here this should work exactly the same way on windows proper on linux proper on mac pretty much any operating system that you will be using this should be exactly the same so there's no no real differences there and uh what we're actually going to be doing today to kind of prompt our learning of the um of the borrow checker is an exercise that is at first easier seemingly easier and more simple than what we did yesterday which was writing a command line utility key value store database today all we're going to be really doing is looking at some very short very um simple code snippets that in other languages would be kind of trivial code but in rus present us a little bit of an issue because we run up against the borrow checker and for good reason i one of my goals for today is to convince you that the borrow checker is not there to make your life miserable but is actually providing some real utility um so we'll look at what kind of bugs actually the borrow checkers uh is saving us from all right so let's get started as always when you're writing russ code you usually start by creating a new cargo project and again cargo's rust dependency manager build tool um all wrapped in one and you do that by saying cargo new and we're going to say cargo new borrow just as the name all right and that creates a new executable application for us and as we saw yesterday there's not too much to it so i'm just going to open this up nbs code right here oh and way too big all right and let me go ahead oops and resize this so everybody can see it well um and open up our main dot rs here where we have our main file here so um again we can go ahead and just run that real quick just to prove to ourselves that it's working cool so we have uh hello world being printed out to standard out here and this is just what cargo kind of creates for us by default when we create a new project and we're gonna we're gonna fill it in with different things so what are we actually going to be uh building today well i want to start out by modeling a group of people and so i think the best way to do that in rust is by having a struct called person and let's say what the the information that we want to keep about the this person or these people is their age and uh the age let's say you know most people are between 0 and 100 120 at the very very highest end and so uh i think a u8 an unsigned 8-bit integer is perfect for modeling that um and let's do height here and i'm just going to do let's say height in centimeters um and i don't know u8 is maybe a little bit too small for that but we'll do it anyway so all the way up to 255 uh 255 centimeters um which is you know if you're taller than that you're quite tall and i i'm almost two meters tall so i know i know that that's quite tall all right so i have a a struct here and a struct is unlike a class in other languages of struct is really just kind of data bundled together just uh two two uh unsigned eight bit integers in this case all right and so um let's say in our main function instead of printing hello world here we're going to create a collection of of persons collection of people and so we call that people here and you know collections and rust typically end up being vectors and vectors are growable linear collections of things you might know them by the name array in other languages arrays and rusts are fixed sized things vectors are growable so if we know exactly we need just five people and we'll only have five people no more no less then we can use array but um but we don't know how many people we're going to have in this example so let's go ahead and create a vector and we're going to use the vector macro here now you you'll see here i was having some issues with rust analyzer yesterday because of i was playing with it before the stream and ended up messing with the configuration got that fixed thankfully so today we've got that going and you can tell that um this is not code that i've written obviously this is just my rust analyzer showing me the type that people is here and it's a vector of and it doesn't know what it's a vector of because we haven't given it enough information to really tell what it is a vector of but we're going to provide a various person structs inside of here in order to make this easier just as a recap of some of the things that we did yesterday i'm going to create an impul here and if you were around yesterday you'll know that impulse are for creating uh functions that are associated functions and methods that are associated with with different types so we're going to create a new function here which we learned yesterday is just a convention for functions that create a certain type so there's nothing special about new it's just a name that we've picked uh and you know we'll say person here and we'll pass in to our function here an age and a height and so and we can do age age height height now a cool a neat thing that russ stole from javascript is that when the field name and the variable name are the same um you can just go ahead and do it like this so this is equivalent to what we had before as a shorthand all right um [Music] so uh chad is asking if if this is a beginner thing um this is definitely uh aimed at beginners uh of rust so if you're if you're an advanced user um we may not cover some things that you're that you've run into before um but we're aiming for people that have seen rust before let's say yesterday and uh so have a basic ish familiarity with the syntax and stuff like that but don't worry you can ask questions if you don't have it and then really with a focus on uh on bar checker if you have no experience whatsoever with rust this might be a little fast at the beginning but that's why we're doing this recap here so um don't don't hesitate to ask questions when when you see something that you don't understand but today we're really going to focus on specifically on the borrow checker all right and we haven't even really talked about what the borrow checker is but we'll get we'll get to that in just a second we're just kind of writing some code here this is a little bit of a recap from from yesterday so i'm just going to call this new function here with you know i don't know how old is this person i'm 31 years old and i am 197 centimeters tall and let's say person the second person here is going to be uh 58 and going to be 160 centimeters tall that sounds about right [Music] all right so we have our vector here and you can tell that rust analyzers now knows what's going on with uh with our people vector here it knows that it's a vector of persons and let's imagine that we want to like like you know this example is going to be very simple but imagine we we have a function that we need to write called first and it is going to take in this collection of of persons so we collect this people collection so we'll call this people and it's going to take in a vector of persons and it's going to return the first person in that collection so this is you know this should be pretty familiar too if you've done some programming before um you can imagine that you would write something like this right there we go now the code is not going to compile and that's exactly why i've written it this way we're going to talk about why it's not why it's not compiling all right so presumably we can say like the first person is by calling this first function here passing in the people vector and that will give us the first person and then you know we got the first person so we can go ahead and say like the person is blank years old and blank centimeters tall and we just gotta say uh first dot age here and first dot height all right i'm gonna widen this out just a little bit here and maybe go down one so let chat let me know if this is uh too small for you and i can bump it back up all right so any questions here it seems we have a question about why there's no return um explicit return so it is totally legal and valid rust to do this as well um of course it's still not compiling but uh the return is totally fine to do here rust is an expression based language and what that means is that the last element of your functions are implicitly returned here so whatever's last in your function will be returned if you're familiar with languages like ruby or something like that then you'll be very familiar with this concept a lot of functional programming languages work this way you don't have to you can do early returns if you you know if you want to do some early returning you know some guard statements and return early that's totally cool and stuff but you don't need return if the last thing um you know to return the last thing here all right okay so we've written some code let me know um if there's anything uh about this code that you want to talk about but this is kind of the example that we're going to start with and we're going to really explore the borrow checker and why this code here doesn't exist doesn't compile deeply so first of all what is the borrow checker well rust is a systems programming language and it does not have a garbage collector what that means is that the memory inside of your program is not managed by a garbage collector as you would expect in java c sharp javascript swift whatever and yes swift has garbage collection it's a different type of garbage collection than than other languages it's not a tracing garbage collector but it's still a form of garbage collection rust does not have that rust has the same form of garbage collect or sorry the same form of memory management that c and c plus plus have in that it is up to the programmer to manage memory but with the caveat and the difference to cnc plus that the memory management that you provide as the programmer if you use rust in the safe variant so there is a way to turn this off but if you use safe rust you cannot get it wrong you might be able to leak some memory so that's that's not your not protected against that but you will never have any of the typical memory management issues that you would have in cnc plus plus if you've done any cnc plus plus before where you have something like use after free where you freeze some memory and then you accidentally use a pointer to that memory afterwards that's impossible to do in rust double free all these typical things and we'll talk a lot about these um as we go along so you got to get your your um mind set to think about these things in terms of memory management and in terms of when memory will be freed and that's exactly what we're going to be talking about today we can no longer rely on a garbage collector to just like you know free that memory whenever we're not using it anymore we don't care when it happens but just like you know at some time when i'm not using it you can go ahead and free it we don't have that luxury and rest we know we will have to be keenly aware exactly when everything uh is is cleaned up for us all right so there was a question in chat um about some syntax here this vec exclamation point a vector is a growable collection in a lot of languages you just call that an array arrays and rusts are fixed size vectors are growable collections otherwise they're basically the same thing and this vect exclamation point is simply just a a macro that's what the exclamation point signifies print line and background macros that creates a vector and pushes these two elements onto it we can write this without using a vector but we would have to create the vector first and then individually push each item onto the vector this fact does that all for us so this is a convenient shorthand for doing that all right um and there was a question why are both the var and function called first i don't know because i'm bad at naming things i guess uh what would you like to call it f or person let's call it person hopefully that's a better way to so that we don't get confused here all right so now that we're in the frame of mind of thinking about uh memory management and things like that we we should ask ourselves okay when we when we allocate memory when will that memory be freed and if you if you know anything about the heap versus the stack you'll know that when we create a collection of something we're going to have to put it on the heap because this is dynamic memory we put it on the heap and at some point in our program we will have to free that memory and in cnc plus you would typically allocate memory with a function called malloc and then free that memory with a function called free and rest you don't typically uh do those things manually vec here will allocate uh space on the heap for two person structs to to live in and then when will that memory be freed and this is the core concept of rust it comes from the idea of ownership now what does ownership mean it means that every uh value and rust has an owner a variable name or better set of binding like people here this people variable name this people binding owns this vector so when we say it owns it what we mean by that is it's in charge of its memory and when a binding goes out of scope which we know about scope and any language right this is this is a scope here right and when people goes out of scope here the thing that it owns will be freed so when we look at this code for instance we can see okay people here gets created and people goes out of scope at the end here and that's when the memory will be freed now if you've done some rust programming you know that's that's not completely true the way that we've written the code after all doesn't compile but that is 100 true if we go ahead and say this right here so people gets allocated onto the heap and when people goes out of the scope because it owns the memory um inside of vector and somebody's asking for a bigger font yes hopefully this is is that viewable when people goes out of scope then the memory will be freed so you have to remember that and rest you always should have in your head okay a piece of memory like this vector what owns that memory if you can answer that question then you can answer the question of when does that when does that memory get freed all right okay so if we write the if we write a function like this there's another concept in rust called moving and what moving does is transfer ownership from one binding name to another all right so when we say when we pass people into our first function here what happens is is we move the ownership from this people binding into the people binding right here of course we all know this can be you know let's call this ps for persons so now they're not named the same thing so ownership of people is being transferred from here from this people binding sorry the ownership of this vector is being transferred from this people binding to this ps binding so we've moved ownership so now since we've moved ownership and that as ps owns the vector we know where this vector will be freed it's whenever ps goes out of scope and so this vector will no longer be dropped at the end of the of the function it will be dropped or it will be freed at the end of this first function all right so we we have this idea of ownership a piece of memory belongs to a binding and whenever that binding goes out of scope we free the memory but we can transfer ownership when we move variables and there are various times when moves happen one of them that we're seeing right here is we are moving uh the vector into a function so when you call a function whatever your arguments get moved into that function that's just how functions work in rust any questions about this all right all right good it seems like some things are clicking before that's good all right so we've moved the people vector into the first function this vector now is owned by ps and we know that we're going to drop psd into first that's that's great okay now let's take a look let's dare to take a look at what actually the uh the error message that we're getting it says cannot move out of index of st of vec of person move occurs because type because it has type person which does not implement copy trade okay so okay what the heck does this mean so we learned that calling functions the arguments get moved into the function another thing that moves values is by indexing into a collection here so we are trying to move the ownership of the first person the person at index zero out of the vector and return it from our function and you might be wondering okay that shouldn't that work but let's think about this okay if we move the first person out of the vector the vector itself is going to be freed or just uh destroyed at the end of first but we're trying to return the person here from the function we can't do that why because ps the vector and of course the vector when it's destroyed all of its elements also get destroyed ps will be destroyed at the end of of the first function here at this line but we've moved the person out of here so we would end up moving it somewhere else and then later on person here is a person owns this uh this person struck and it will be destroyed here we would end up destroying this person struck twice we would call the destructor twice on this person struck we would be freeing it twice this is a double free um in a language like c this is totally valid to do and in this case you know this case it probably would work um you know rust right here is being quite pedantic this case it you know they're most likely uh things would work but actually you don't know um you know we're not freeing anything and we're not using anything in the heap anymore but if we were to write more code that actually allocated more things in the heap this memory that person is involved that that person uses might be overwritten with something else all right so how do we get to this uh to work we want to there's there's multiple ways right but the first thing that we we should think about is is there a reason that we're moving first the the person vector into first why are we moving it into well so far we're moving in there because we don't know any other way right we don't know anything other than to move into a function but this is where borrowing in rus comes in so instead of moving the thing into the function you just let the function borrow it and say hey like you know i still am the owner here you know i own this thing i will destroy it but like you can have it for a little while and what rust does is ensure that the time that this this function is borrowing the the vector the the vector here is not longer than when we will eventually destroy the thing so how do you borrow a value in rest well it's quite simple you just add an ampersand before it so now um and we're getting an error here because it's saying hey you are passing ownership of this vector but you said you would give me a borrow of the vector okay okay that's fine i'll give you a borrow instead okay so now first is borrowing vector and that means that we don't move people into the first function so ps won't be destroyed here because ps doesn't have ownership over that vector it just is a is a borrow and so where will the vector be destroyed it will be just like way back when we first started writing this code it will be destroyed at the end of main all right so you can think of this just like kind of uh you know books as a good a good analogy here i own a book and i can either transfer ownership to you and actually hand you the book and say you are in charge of it now you can do whatever you want you're in charge of making sure it gets recycled properly when you're done with it or i can say hey you can borrow this for a little while but i'm going to need it back and that's exactly what we've done here instead of transferring ownership to the first function we just say hey you can you can borrow it and someone in [Music] in chat that uh this is kind of passed by reference instead of path by value yeah um there are subtleties here that that we're going we're getting into that are different than in some other languages when it comes to that but roughly what you can think of here is pass by pass by reference instead of pass by value if that's a comfortable thing for you at the end of the day what is this you know in machine code this is probably just going to be a pointer of some sort but we're at a higher level now we're not trying to think about pointers and stuff like that we're just thinking about borrows and ownership and russell westbrook is asking is ampersand a pointer to a static variable i wouldn't say it's a static variable um i mean if you want to think of it that that way you can um static variables and rust have have a very specific meaning i'm just going to say that at the end of the day you can think of a reference this is called a reference so you should use that nomenclature but at the end of the day yes it's probably going to be a pointer all right so the code is still uh not compiling because we're still trying to take ownership of the of of this person um wouldn't it be great if instead of taking of trying to take ownership of the first person we just say hey you like you've let me borrow this people collection i'll send you back a reference to the first person so that's exactly what we can do we can say now that instead of trying to take to move the first person out of the ps vector we're going to return a reference to that first person and it's still not compiling because it's saying hey like you're trying to return a person like an owned person the the uh like ownership of this person um but instead you should uh be taking a reference and so that's really easy to add with another ampersand so now the code finally compiles we have some warnings here that's what the yellow means just some like hints because we're not using person for instance um but uh effectively what we've done is we've said i don't first is no longer taking ownership it's no longer going to destroy that vector it's simply borrowing it and we're going to return back a reference to the first person in here and now person up here has ampersand as ampersand person it is a borrowed person instead and we can still use it just fine in our print line here all right if we run it we can see the person is 31 years old and 197 centimeters tall all right this right here is basically um half of what you need to know about the borrow checker and rust so this is really important to know this that the the difference between moving values transferring their ownership basically saying to another variable you're in charge now of freeing this thing and then we have borrowing which essentially says you can have this for a little while but i'm going to need it back all right and chad is asking is this the same thing um as string capital string versus ampersand stir yeah it's very related in the fact that ampersand string is an owned string that means when the variable that's tied to it is goes out of scope it that string will be freed and all the the string data will be freed will be you know freed from the heap and ampersand stir that we saw yesterday is simply uh borrowing and looking it's like a string view so there's there's a little bit of difference with ampersand stir that we probably won't get into today um but you can effectively think of it that way there's there is um there's also ampersand capital s string as well which is truly just a borrowed string maybe we'll talk about that at the end what the differences are there any more questions uh about this all right so um let's go ahead and say that we want to uh create a a function called print and what print is going to do is take a person by value so it takes ownership of person and it's simply going to print this out all right now we know where will this person be destroyed well we'll be destroyed when it goes out of scope because we have ownership person person this person uh variable is in charge of the person struct it owns it and when it goes out of scope it will destroy it there's a question is it possible to lose the reference during borrowing no it's not possible to just lose it um rust ensures one one way that rust references are different than pointers for instance is that references are always valid they always point to valid memory and rust statically confirms that this is the case if if you find that to not be a case then you have found a bug in in the rust programming language and they're never null so we know when we pass in an ampersand vect here that we have a valid reference a valid pointer to a vector of persons all right and we know that for instance we can't oh sorry if we try to call print oh sorry this print function with our person here it won't compile because it expected an owned person and we gave it a reference to a person now there are ways to to you know turn a reference into um an owned value but we're not quite there yet we'll look at that in just a second all right but if we go ahead and just change this now to ampersand person to take to borrow it then it's fine and of course if we want to like print multiple times that's also fine but imagine let's say let we had an owned person person two here we're gonna say person new um the person's going to be 17 and 183 centimeters tall all right i oops mean this here there we go so we have person two here and we're going to change uh print back to taking it the owned version right and if we pass in person two this is fine right we person two owns this purse instruct so we can pass it we pass ownership into the print um function here this is totally cool what happens if we try and do it again we can't do it why because we've passed ownership into the first print the first call to print here we can't pass ownership again because we know when we pass person to into print print will drop will destroy will free that person so if we were able to do this where we call print twice with the same person it would be freed twice and that is a double free so we are preventing here double free all right there's a question about have you considered rewriting visual studio and rust i have considered it yes but i am in no way connected to the visual studio team so it doesn't matter what i consider and i'm pretty sure the visual studio team has not considered rewriting uh visual studio and rust the reason is visual studio is very old has a lot of code in it and rewriting in a rust would take years and years and years and years and years rewriting it in any language would take years and years and years and years and you know it's up to the visual studio team to decide if that's worth it or not and i i think they probably have determined that it's not worth it which doesn't seem like a terrible decision all right so any questions about ownership here we've passed ownership into print uh ownership of person2 into print and then we try to pass ownership again but we can't and if we look at the um and i'm just going to pop this open and do a cargo check real quick to see the nice clear oops check and this is what rust is telling us use of moved value person two move occurs because person two has type person and we haven't talked about the copy trait in just a second we'll talk we'll talk about that we've moved into print on line nine and then we're trying to use it after we've moved it so we can't do that not only can we not move it into things but we can't you know let's say we just wanted to like get the age of person two here we can't even do that right because person two has been moved into print there's a question i'm not sure about ps declaration it is declared and initialized the same time in fn first uh nature hermit can you ask can you perhaps ask the question in a different way i'm not exactly sure what you need ps here of course is an argument to our function so whatever we pass into first here that's what we will bind to the name ps so for instance uh up here this people this reference to people will be referred to by ps it's a function argument just like in any other language so there's a question what's the reasoning behind this implicit mutation can you can you ref um clarify what you mean by implicit mutation because we're not actually mutating anything here we are just we are destroying it of course this is all compile time right so uh we're not actually changing the value we're just saying russ is just saying hey you can't do that because you've passed person two into print so there's no mutation going on we're going to look at mutation in just a second if you can clarify what you mean and be happy to answer the question all right let's take a look at mutation what happens if we want to write a function that simply changes the age by year let's call it birthday now of course we can take in a person here and person age equals person dot age plus one this works totally fine it doesn't work totally fine because in russ everything is immutable by default so actually we have to say hey we're changing the person variable here so we have to declare it mutable all right this works fine but it's maybe not the most useful function in the world because where will person be destroyed at the end of this function so we'll call birthday the person will age will increase and then we will will free its memory maybe not the most useful can we instead borrow it like this and we cannot cannot assign to person.age which is behind an ampersand reference and let's see if we actually uh sorry if we go ahead and yes even rust is telling us what it thinks we should do so help consider changing this to be a mutable reference so there are two types of references in rust there are immutable references which we've already seen this ampersand person and there are mutable references which we have not seen which are ampersand mut just like this and we can only mutate through a mutable reference we cannot mutate through an immutable reference and now birthday can works just like before we can say um you know birthday and we can pass in immutable reference to person two here and we have to say hey we're going to be mutating person two again rest is immutable by default so now this all works fine it's compiling fine this totally works fine does this make sense to everybody there's some talk in chat about move semantics versus copy semantics we're going to get to that in just a second so hold on yeah so um there was a question of before you know when we were calling print twice with person two like we passed person two into this print function and then we could no longer use it that's kind of the point like we have declared that the function print here should be responsible for fraying the thing of course we can change print to not do that now we have said that print shouldn't destroy a person it should merely borrow it so we have control over when person will be borrowed or not all right and again we don't have a garbage collector here right we don't have a garbage collector that can make these decisions for us we have to decide when our memory will be freed and we are telling rust in print should free person here when we declare it like this and when we declare it like this we say hey print should only borrow it it should not take ownership and therefore free that that person destroyed that that person all right okay so we saw above that we were able to pass mutable ref as many mutable references as we want can we pass as sorry pass as many immutable references as we wanted to when we called um uh let's see here we can call first for instance many times so because we're passing in an immutable reference to people this is totally fine we're passing people over and over and over again we get a minute a lot of mutable references back here it's just complaining that we're not you know we're not using person anymore um that's fine can we do the same with with birthday here what if we try and mutate it twice okay we can that's great but what happens if we move this out and say we have a mutable person here now mutable person is a variable that is a ampersand mute and we can pass it into birthday and pass it into birthday and this also works fine it's totally fine to do all right so it's totally cool to discreetly pass in immutable uh mutable uh references to things and multiple different functions that's that's fine to do all right any questions about this um so ps on line three is a reference to people but but ps declared in first is a copy so it's not a copy ps here is not a copy at all it is a reference to the previous vector it is literally it's pointing to it if you've done any pointers before it really is just saying hey the vector of people somewhere else so it's not taking a copy it's not copying it at all and crateless is asking you cannot use person2 after uh this call to print that is correct if we try and do that it will fail to compile all right is it necessary to make a call that destroys an object by the end of maine no it is not necessary to do that because again when own when bindings that own a particular piece of memory go out of scope they will be destroyed so people owns this vector here and when it goes out of scope down here at line 15 it will be destroyed there's a question why can't you use ampersand mutt p2 after line 22 um can you clarify that excellent dragon i think you should be able to that works fine all right um we are reaching the end here so we need to talk about one last thing the one last thing that we need to talk about is the differences between immutable references and mutable references now so far what we've seen is they seem to be the same except that when you declare a mutable reference you're allowed to mutate and when you declare an immutable reference you're not allowed to mutate but there's actually an important distinction between that what the important distinction is is that mutable references you're only allowed to have one of them at a time all right so here our our mutable person on line 11 is a mutable reference to person 2 here but if we try to take another mutable reference to person 2 and rust is being very uh clever here because we're not actually using it we have to use it it no longer compiles and let's let's take a look at the error message that we get so cannot borrow person two as mutable more than once at a time we see the first mutable borrow occurs here and the second mutable borrow occurs here and why is this this is a fundamental rule of rest in rust you can have either as many immutable references as you want at a time or and this is exclusive or so it's one or the other or one mutable reference all right and we are violating that rule here by having two mutable references we're only allowed to have one mutable reference at a time so we're not allowed to do to do that and we said we're either only allowed to have one mutable reference or as many immutable references what happens if we try to take an immutable immutable reference here again and this this is maybe a bad name now because it's no longer mutable person two um getting a bad error message there it's not really bad but this gives us a uh let's see okay so um [Music] real quick unfortunately we don't have a nice we don't have a function that just takes a immutable reference let's say h is going to uh let's do print print age is just going to take a person a immutable reference to the person all right and we will just say the person is blank years old all right so again this is taking an immutable reference up sorry person.h this is taking an immutable reference and so person will not be destroyed here we're simply borrowing it so up here we can go ahead and call print age with our let's call this immutable person2 and now we see the error we cannot borrow person2 as immutable because it's also borrowed as mutable so this is exactly what we have to deal with we are only ever allowed to have one mutable reference to a thing or as many immutable references as we ever want to all right someone's asking and chat about rc and arc unfortunately i don't think we're gonna have enough time to tackle rc and arc today um but i'll put on this on a little bit later i have my own stream um where i stream about rust and i'm more than happy to have future streams where we kind of continue this conversation and talk about um talk about those topics that are the next step in and russ borrow checker i'll go ahead and throw up my information here um this is my twitter handle up top at ryan underscore levick you can follow me on twitter and i then i tweet about when i'm gonna go live on twitch and this is my twitch where you can follow me as well so if you're interested in learning more about rust then definitely give that a follow just leave that up for just one more second all right i want to talk about one more thing before we um slowly bring this to a close and that is this copy trait that keeps popping up so let's go ahead and get rid of this code real quick i'm going to get rid of all this code blah blah blah and for instance um when we tried to call print multiple times here where we get this answer um well let's see i need person two again so if we try if we create person two and we try to call print multiple times the code does not compile and it keeps making reference to this copy trait so move occurs because person two has type person everything that we've been describing so far about moving values from one variable to another are summed up with this idea called move semantics so rust has this idea of move semantics and all that means is exactly what we've been talking about so far when we pass variables into functions they get moved into functions rust moves things by default now if you're coming from a c plus background you know that c plus does not have move semantics by default you have to explicitly move things c plus has copy semantics so instead of moving things into functions you copy them into functions but what happens if we want that behavior let's say we we don't want to have to deal with um moving things all the time in fact our person struck down here is just two numbers like it's totally fine to just keep copying it all over the place that's totally cool it's only two numbers copying is really not that expensive how would we go ahead and opt into this copy semantics so that when we pass a person into a function instead of moving it in it simply copies the thing we do that by using this funny little syntax called derive and we derive a trait and trait is just simply like a marker of functionality that a type has you can think of them like interfaces in other languages we have to derive copy here now copy will then tell you i can't be copy unless i'm clone so we have to also derive clone and what clone is is just like copy except that it's explicit so if you want to be able to copy values by calling a you know a function to actually copy them you have to implement the clone trait here and copy simply says make that implicit so now our code up here compiles because person 2 is no longer moved into the print function it has copy semantics it's now copied into the print function and we can see that if we go ahead down here and say um you know print now let's have a birthday before we print so before we print here and we have to declare this as mutable before we print here where the person will have a birthday all right if we go ahead and run this cargo run you can see that this person too this person too is 32 years old 100 centimeters even though we had a birthday twice for each time that we called the print function because we copied the person into that print function they will end up having the same age over again because they were copied in an excellent dragon was what if you only want this behavior on in one specific function unfortunately well you can have that you can as long as that type implements clone you can specifically call clone on that so let's say we remove copy here our person this will no longer compile up here because person2 no longer is copy it no longer has copy semantics it now moves into print just as before but person implements the clone trade so if we want we can call clone on it and this will literally clone the value and why is it complaining now oh because it's been moved in we have to do it the other way around we clone here we get a copy of person two and move that into uh print but person two has not moved and so now we're allowed to move person two into print but of course if we call it a third time it will complain so if we wanna be oops if we wanna be able to do this we'll have to clone this one as well so this is how you get it sort of on a per function basis so there's a question is it quite tricky to refactor rust code um actually no rust code tends to be extremely easy to refactor surprisingly the reason is is because the compiler's quite picky and so as long as you get it to compile which you know at first if you're not used to rust or something like that it might be tricky to refactor because you're constantly having to think through these things but you know when you get used to rust this all becomes second nature you just start thinking in terms of borrows and moves and things like that and then you can simply refactor knowing if you forgot something if you uh you know forgot to to touch a file over here or change this function over there or something like that you don't have to worry about it because the rust compiler will tell you hey you forgot it over here you're doing this thing even though you change the code over here to change from uh copy to to move and it will complain at you so um in fact like it's there are off many stories of people taking code bases written in rust that are hundreds of thousands of lines long doing massive refactors on them and then uh once they get the code to compile again it ends up working like it did before because the the compiler is very good at um what we're doing here is essentially proving to compiler that we are creating a correct program and the compiler once it's satisfied says okay you're allowed to run this program now other languages like cnc plus plus take a very different approach to this where it's quite easy to get something to compile but will it be will it work correctly is a whole other story and rust kind tries to front load the the cognitive load of getting something correct to the compile stage instead of at the run stage there's a question is it possible to write c plus in a rusty way yes absolutely and i think if you um you know if you write c plus for work or if c plus plus is your main language i still would highly recommend learning russ because you can take a bunch of the learnings that you have from rust and then apply them to your c plus plus code and if you do that your c plus plus code should become much easier to maintain you won't have the same level of you know the c plus compiler will still not prevent you from doing something wrong but you can apply patterns that you have to do in rust to c plus plus and even though you're not forced to do it that way they're still good patterns and orc blood is asking don't know either c plus or rust which one should you learn my answer to that is always both but if you have to choose one c plus plus is definitely a much more established language so if you're just like wanting to get a job let's say in the gaming industry or something like that you'll probably have a lot more luck with c plus plus there's simply just a lot it's an older language it's been around a lot longer it's more stylish so there's going to be more opportunities in c plus i personally find rust a lot more a lot easier to learn i spent a long time trying to learn c plus and would always it's a it can be a very frustrating language at times this is my personal experience but for me personally it was a very frustrating language to learn it's a very very complicated language there's a lot of features in it rust is um is tough at the beginning but um you know it's you know once your code compiles that you really have done something right um that you don't have to sit there in a debugger debugging why your code is segfolding and stuff like that because there are no seg faults in rust and safe rust you cannot have a segfault if you get a segfault fault there's a bug in somebody else's code which is good to know all right so this we're gonna we're gonna end around here um feel free to throw up any last questions if i missed a question um uh please ask it again um and we're gonna i'm gonna end with a couple of words here we've taken we've taken a look here at the rust borrow checker we've learned a couple of things that a bind a piece of memory is owned by a specific binding and when that binding goes out of scope that memory is freed we can move ownership between variables for instance when we take an element out of a vector when we pass something into a function we move that that the ownership from one binding to another and then that new binding will be responsible if we don't want to move we can borrow and we can borrow immutably or immutably but we can have as many immutable borrows as we want or one mutable borrow this is very important it can have either or but not both at the same time and if we don't like this whole move semantics that we have for types where it makes sense where all of its fields implement copy then we can go ahead and implement copy as well and now our type has copy semantics instead of move semantics all right now this has been a whirlwind tour if you feel like you are in a stable position right now with a russ barrow checker then you are light years ahead of a lot of other people this this takes a while to kind of settle in in your brain if you're not fully comfortable with everything that we've talked about today don't worry this will be posted on youtube it will be on on twitch go ahead and watch it again take a look at the the um the rust book which is on if you'll find it on rustling.org um this is a great resource for this um rust by example is really great there's rustlings there's a whole bunch of uh of different resources for kind of working through it um and realize that this is the core of rust so if you're struggling with getting code to to compile here don't worry um it's it's not you this is the tough concept about russ but it's very very worth it once you learn this then you can feel comfortable about the code you write and never ever experience a segfault in a systems programming language that's a huge deal i almost never use a debugger when i when i use rust so uh because you know what's their debug um all right real quick uh a couple of last questions um just to end on um so can you edit a fun definition to pass by copy so it's not the function definition that determines whether a value is passed by copy with copy semantics or move semantics it is the type itself so right now oops right now our person type is declared to be copy so it will be copied when passed into um into a function but as soon as we remove this it will now be moved in so no longer copied but moved into a function so and there's a question how far do you intend to go with this series unfortunately this is the last that i will be on this channel so we're just having a rest week here on microsoft developer twitch but over on my other channel i basically only stream about rust or recently did a series on elf executables in linux so i do some computer science some some linux stuff and things like that um but if you're interested in that let me know um it's easiest thing to do is follow me on twitter and just ping me hey it would be great to see more about this um i would be happy to do a continuation of this series over on my channel so please do let me know um uh and about uh joining eric st martin's uh stream he's my colleague so eric and i have talked about uh me jumping on his stream i we're in different time zones so it's not always easy uh to do but i would absolutely love to be on eric's stream and one last thing to throw up here's my social information here at under ryan underscore levick is my uh twitter handle and uh below that is my twitch channel so make sure to follow me there if you're interested in this and um i believe that was all the uh the questions that we had um so thank you very much i'll i'll be sticking around a little bit in chat after this ends and of course i'm on twitter feel free to hit me up there um and i hope everybody uh had a good time with the stream today and has a good rest of their day alright bye bye
Info
Channel: Microsoft Reactor
Views: 3,264
Rating: undefined out of 5
Keywords: coding, languages, framework, rust, borrow checker, microsoft
Id: BaYbxv1JF64
Channel Id: undefined
Length: 67min 34sec (4054 seconds)
Published: Fri Sep 25 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.