1 00:00:06,630 --> 00:00:09,990 - One of the main goals of Rust as a programming language 2 00:00:09,990 --> 00:00:13,920 and as a library is to simplify memory management 3 00:00:13,920 --> 00:00:15,750 and to avoid some of the errors you can get 4 00:00:15,750 --> 00:00:17,160 in other popular languages 5 00:00:17,160 --> 00:00:20,460 of a similar ilk like C++. 6 00:00:20,460 --> 00:00:24,420 So Rust achieves memory safety via several techniques 7 00:00:24,420 --> 00:00:26,130 such as stack allocation. 8 00:00:26,130 --> 00:00:28,020 When you create an object in Rust, 9 00:00:28,020 --> 00:00:30,240 normally, you allocate it on the stack. 10 00:00:30,240 --> 00:00:32,700 So you avoid all the potential difficulties 11 00:00:32,700 --> 00:00:34,980 of heap-based allocation 12 00:00:34,980 --> 00:00:37,050 where you have to allocate the memory, 13 00:00:37,050 --> 00:00:40,350 remember to delete it, don't try to delete it twice. 14 00:00:40,350 --> 00:00:45,350 So that's much more potential for error in C++, 15 00:00:45,510 --> 00:00:48,690 where objects are allocated on the heap a lot, 16 00:00:48,690 --> 00:00:51,360 whereas in Rust, objects are mainly allocated on the stack, 17 00:00:51,360 --> 00:00:54,540 much simpler, management model for memory. 18 00:00:54,540 --> 00:00:57,330 We have references rather than pointers. 19 00:00:57,330 --> 00:00:59,280 Rust does have pointers, 20 00:00:59,280 --> 00:01:01,350 we'll see that at the end of this lesson, 21 00:01:01,350 --> 00:01:03,600 but in most cases you just use references 22 00:01:03,600 --> 00:01:07,710 and references are more protected than using raw addresses. 23 00:01:07,710 --> 00:01:09,240 Rust also has the borrow checker. 24 00:01:09,240 --> 00:01:10,620 Of course in the compiler, 25 00:01:10,620 --> 00:01:12,120 the borrow checker stops you 26 00:01:12,120 --> 00:01:14,880 from accidentally doing something 27 00:01:14,880 --> 00:01:17,520 like having two multiple references to the same object 28 00:01:17,520 --> 00:01:19,170 which could conflict with each other. 29 00:01:19,170 --> 00:01:22,320 Rust only loves to have one mutable reference at a time. 30 00:01:22,320 --> 00:01:25,890 So the borrow checker helps to ensure the integrity 31 00:01:25,890 --> 00:01:27,750 of the data under the covers. 32 00:01:27,750 --> 00:01:31,980 So that's a saving, in terms of safety. 33 00:01:31,980 --> 00:01:34,473 So generally, avoidance of pointers in your code. 34 00:01:35,940 --> 00:01:37,440 So having said all of that, 35 00:01:37,440 --> 00:01:40,440 there are still some occasions where you do actually 36 00:01:40,440 --> 00:01:42,120 need to allocate something on the heap, 37 00:01:42,120 --> 00:01:46,290 such as allocating a massive amount of memory. 38 00:01:46,290 --> 00:01:50,010 So for example, if you need to allocate 100K, 39 00:01:50,010 --> 00:01:51,360 you can't allocate that on the stack, 40 00:01:51,360 --> 00:01:52,440 it's just not big enough. 41 00:01:52,440 --> 00:01:56,220 So you would have to allocate on the heap in that situation. 42 00:01:56,220 --> 00:01:58,560 Also, if you have a recursive data structure 43 00:01:58,560 --> 00:01:59,823 like a binary tree, 44 00:02:01,050 --> 00:02:04,260 that's difficult to manage without using pointers 45 00:02:04,260 --> 00:02:05,940 and objects on the heap. 46 00:02:05,940 --> 00:02:10,940 So if you do need heap allocation in Rust occasionally, 47 00:02:11,520 --> 00:02:12,810 the way to achieve that 48 00:02:12,810 --> 00:02:14,340 is using something we call a Box. 49 00:02:14,340 --> 00:02:16,920 There's a structure type in Rust called Box, 50 00:02:16,920 --> 00:02:19,020 which is a smart pointer. 51 00:02:19,020 --> 00:02:23,040 Box object, internally, holds a pointer 52 00:02:23,040 --> 00:02:24,693 to something on the heap. 53 00:02:25,950 --> 00:02:29,640 So it's like a, it's a bit like auto pointer in C++, 54 00:02:29,640 --> 00:02:31,170 if you remember that. 55 00:02:31,170 --> 00:02:33,750 So here's an example usage, it's quite straightforward. 56 00:02:33,750 --> 00:02:35,640 When you say Box new, 57 00:02:35,640 --> 00:02:38,610 it'll understand what type of object you've allocating. 58 00:02:38,610 --> 00:02:41,643 And this value here will be allocated on the heap, 59 00:02:44,130 --> 00:02:45,330 and the Box object, 60 00:02:45,330 --> 00:02:46,650 I've got a Box number here, 61 00:02:46,650 --> 00:02:47,763 lives on the stack, 62 00:02:49,830 --> 00:02:50,853 Box number, 63 00:02:51,750 --> 00:02:54,480 and the Box object has a pointer 64 00:02:54,480 --> 00:02:56,523 to the heap-based storage like that. 65 00:02:57,600 --> 00:03:00,333 So the Box object itself lives on the stack. 66 00:03:01,260 --> 00:03:02,940 The memory that you're referring to 67 00:03:02,940 --> 00:03:04,923 lives on the heap like so. 68 00:03:06,360 --> 00:03:08,130 Well, what if you've allocated an object 69 00:03:08,130 --> 00:03:09,960 and you point into it using the Box, 70 00:03:09,960 --> 00:03:11,940 imagine you wanted to print the value out. 71 00:03:11,940 --> 00:03:14,400 Well, you can either use explicit 72 00:03:14,400 --> 00:03:16,200 or implicit D referencing. 73 00:03:16,200 --> 00:03:19,710 So if Box number is effectively a pointer 74 00:03:19,710 --> 00:03:21,930 to this heap-based storage, 75 00:03:21,930 --> 00:03:23,343 containing the value 42, 76 00:03:24,420 --> 00:03:27,840 you can explicitly dereference the Box 77 00:03:27,840 --> 00:03:30,150 to give you the contents of what it points to, 78 00:03:30,150 --> 00:03:32,550 the contents, 42. 79 00:03:32,550 --> 00:03:34,860 That's explicit D referencing, 80 00:03:34,860 --> 00:03:36,840 but println, is a special case, 81 00:03:36,840 --> 00:03:40,560 the println macro also supports implicit dereferencing 82 00:03:40,560 --> 00:03:41,880 without the star. 83 00:03:41,880 --> 00:03:44,460 When you pass a Box object like that into println, 84 00:03:44,460 --> 00:03:46,440 it'll kind of understand what you're getting at. 85 00:03:46,440 --> 00:03:49,080 And again, it will automatically dereference 86 00:03:49,080 --> 00:03:51,480 to give you the contents 42, like that. 87 00:03:51,480 --> 00:03:52,890 But that's a special case. 88 00:03:52,890 --> 00:03:54,900 Println is a special case in that respect. 89 00:03:54,900 --> 00:03:57,690 Most cases, if you wanna access the value yourself 90 00:03:57,690 --> 00:03:59,220 you've gotta actually do it explicitly. 91 00:03:59,220 --> 00:04:01,140 So if you wanna get the value 92 00:04:01,140 --> 00:04:02,400 and sign to an integer, 93 00:04:02,400 --> 00:04:06,150 you've gotta explicitly dereference the Box. 94 00:04:06,150 --> 00:04:08,880 It's called unBoxing, 95 00:04:08,880 --> 00:04:11,970 that's the term you might see in other languages 96 00:04:11,970 --> 00:04:14,460 like Java for example. 97 00:04:14,460 --> 00:04:19,460 So unboxing, it will explicitly dereference the Box 98 00:04:20,400 --> 00:04:23,190 to give you the contents 42, like that. 99 00:04:23,190 --> 00:04:25,950 So the contents will be then signed 100 00:04:25,950 --> 00:04:28,590 into the integer like that. 101 00:04:28,590 --> 00:04:30,990 So let's have a look at this simple example. 102 00:04:30,990 --> 00:04:33,750 The demos for this chapter are in this folder, 103 00:04:33,750 --> 00:04:36,750 lesson 15, additional Rust techniques. 104 00:04:36,750 --> 00:04:38,850 And for this first demo 105 00:04:38,850 --> 00:04:40,230 we're gonna look at main.rs, 106 00:04:40,230 --> 00:04:41,610 which is obviously entry point, 107 00:04:41,610 --> 00:04:43,260 and then we'll have a at demo_box1. 108 00:04:43,260 --> 00:04:47,190 That's our first example for this section, demo_box1. 109 00:04:47,190 --> 00:04:48,123 Let's take a look. 110 00:04:49,380 --> 00:04:53,433 So in main, I'm gonna uncomment the first called demo_box1 111 00:04:54,600 --> 00:04:57,390 and it's a very simple syntax example of this. 112 00:04:57,390 --> 00:04:58,700 We'll have look at applications of Box, 113 00:04:58,700 --> 00:05:02,910 how you use in the practice a bit later, but for now, 114 00:05:02,910 --> 00:05:04,260 when you say Box new, 115 00:05:04,260 --> 00:05:06,630 it'll allocate this object on the heap. 116 00:05:06,630 --> 00:05:09,510 The Box will have a pointer into the heap, 117 00:05:09,510 --> 00:05:12,450 the Boxed object itself lives on the stack. 118 00:05:12,450 --> 00:05:14,340 And then as I said, with println, 119 00:05:14,340 --> 00:05:16,770 you can dereference the Box explicitly 120 00:05:16,770 --> 00:05:18,960 to give you the contents of what it points to. 121 00:05:18,960 --> 00:05:21,150 Or you can use implicit dereferencing 122 00:05:21,150 --> 00:05:24,840 without the star, println supports both syntaxes. 123 00:05:24,840 --> 00:05:28,410 But if you want to manipulate the value yourself 124 00:05:28,410 --> 00:05:29,940 like I've done here, 125 00:05:29,940 --> 00:05:32,520 then you do need to explicitly dereference. 126 00:05:32,520 --> 00:05:35,587 If you didn't, you'd get a compile error to say, 127 00:05:35,587 --> 00:05:37,470 "This is a Box object, 128 00:05:37,470 --> 00:05:39,750 but you're trying to assign it to an integer," 129 00:05:39,750 --> 00:05:40,590 that doesn't make sense, 130 00:05:40,590 --> 00:05:42,780 you've got to explicitly dereference the Box 131 00:05:42,780 --> 00:05:46,620 and the Box to the contents of what it points to like that. 132 00:05:46,620 --> 00:05:51,513 And then that value should be 42, which we then print here. 133 00:05:52,560 --> 00:05:54,030 So let's run this first example 134 00:05:54,030 --> 00:05:59,030 just to pay due diligence, we're just gonna see the output. 135 00:05:59,220 --> 00:06:01,830 There's not gonna be any great surprise here. 136 00:06:01,830 --> 00:06:04,110 So using explicit dereferencing 137 00:06:04,110 --> 00:06:05,910 and implicit dereferencing, 138 00:06:05,910 --> 00:06:10,320 explicitly dereference, implicitly dereference, 139 00:06:10,320 --> 00:06:12,570 and then to explicitly dereference 140 00:06:12,570 --> 00:06:14,700 where we need to actually pluck out the value 141 00:06:14,700 --> 00:06:17,403 and copy it into the variable here. 142 00:06:18,540 --> 00:06:21,330 So that's our first example. 143 00:06:21,330 --> 00:06:24,360 Gonna look at another consideration here. 144 00:06:24,360 --> 00:06:29,360 The Box structure doesn't implement the Copy trait. 145 00:06:29,430 --> 00:06:34,260 So when you assign one Box to another, a move occurs. 146 00:06:34,260 --> 00:06:36,090 So it looks like this. 147 00:06:36,090 --> 00:06:39,930 If one Box points to value like that, that's Box1, 148 00:06:41,460 --> 00:06:44,670 and you say Box2 equals Box1, 149 00:06:44,670 --> 00:06:48,570 then Box2 would acquire ownership 150 00:06:48,570 --> 00:06:52,890 and Box1 would lose ownership, a move occurs. 151 00:06:52,890 --> 00:06:54,360 When you assign one Box to another 152 00:06:54,360 --> 00:06:56,610 it moves the value into the new Box 153 00:06:56,610 --> 00:06:58,923 and the old Box is effectively defunct. 154 00:07:00,690 --> 00:07:02,730 So when you assign a Box object to another 155 00:07:02,730 --> 00:07:05,670 a move occurs, you can just about see that. 156 00:07:05,670 --> 00:07:08,670 Box does implement the drop Drop trait, 157 00:07:08,670 --> 00:07:09,690 and that's just as well. 158 00:07:09,690 --> 00:07:11,850 Well, it is a feature of the way Box works 159 00:07:11,850 --> 00:07:13,770 to avoid memory leaks. 160 00:07:13,770 --> 00:07:16,170 When a Box object goes out of scope, 161 00:07:16,170 --> 00:07:17,970 the drop function is called, 162 00:07:17,970 --> 00:07:20,973 and the drop function deallocates the heap-based storage. 163 00:07:21,870 --> 00:07:25,983 So the Box object owns the memory that it points to, 164 00:07:26,970 --> 00:07:28,800 when the Box object goes out of scope, 165 00:07:28,800 --> 00:07:33,150 the drop function will do that before the Box object itself 166 00:07:33,150 --> 00:07:34,173 pops out of scope. 167 00:07:35,190 --> 00:07:38,970 So this has consequences when you pass a Box object 168 00:07:38,970 --> 00:07:40,470 into a function. 169 00:07:40,470 --> 00:07:41,850 We're gonna have a look at that now. 170 00:07:41,850 --> 00:07:44,820 In our project we'll run, have a look at main, 171 00:07:44,820 --> 00:07:48,000 and then we'll have a look at demo_box2. 172 00:07:48,000 --> 00:07:52,653 So let's uncomment demo_box2, and let's take a look. 173 00:07:54,150 --> 00:07:56,130 I've got a simple employee structure, 174 00:07:56,130 --> 00:07:58,200 and employee has a name and a salary. 175 00:07:58,200 --> 00:07:59,033 Fair enough. 176 00:08:00,821 --> 00:08:02,400 I've created an employee object here 177 00:08:02,400 --> 00:08:03,810 with a name and a salary. 178 00:08:03,810 --> 00:08:06,510 That object will be allocated on the heap 179 00:08:06,510 --> 00:08:08,820 and the Box object with container pointed to it. 180 00:08:08,820 --> 00:08:13,080 So this Box object, this boxed_em is a stack-based Box. 181 00:08:13,080 --> 00:08:15,150 In that Box is a pointer 182 00:08:15,150 --> 00:08:18,183 and it points to this employee object on the heap. 183 00:08:20,640 --> 00:08:25,350 So now I pass the Box object into a function. 184 00:08:25,350 --> 00:08:27,150 And this, as you can see by this comment here, 185 00:08:27,150 --> 00:08:30,690 this moves ownership of the Box into that function, 186 00:08:30,690 --> 00:08:33,780 because Box doesn't implement the Copy trait, 187 00:08:33,780 --> 00:08:35,220 doesn't implement copy, 188 00:08:35,220 --> 00:08:38,310 therefore, when you pass it in from here into here, 189 00:08:38,310 --> 00:08:39,933 a move occurs. 190 00:08:40,920 --> 00:08:42,990 So this Box is now defunct. 191 00:08:42,990 --> 00:08:45,060 I can't use it anymore. 192 00:08:45,060 --> 00:08:49,200 If I did try to, if I tried to access the Box object here 193 00:08:49,200 --> 00:08:50,340 I'd get a compile error. 194 00:08:50,340 --> 00:08:52,140 We've seen this so many times now. 195 00:08:52,140 --> 00:08:55,350 If you've lost ownership of a Box, if it's been moved away, 196 00:08:55,350 --> 00:08:57,540 you can't then use it here 197 00:08:57,540 --> 00:09:00,870 after the Box object has been moved. 198 00:09:00,870 --> 00:09:03,570 So that would give us one of those common 199 00:09:03,570 --> 00:09:04,830 trying to borrow a value 200 00:09:04,830 --> 00:09:07,773 after its value has been moved away errors. 201 00:09:08,700 --> 00:09:11,820 So the Box object is moved into here. 202 00:09:11,820 --> 00:09:16,820 So this parameter now, it now owns, pointed to resource, 203 00:09:17,160 --> 00:09:20,550 it is explicitly a Box which points to an employee. 204 00:09:20,550 --> 00:09:24,300 So it is a generic type, it contains a point to an employee, 205 00:09:24,300 --> 00:09:29,250 effectively, inside here, I can use the Box 206 00:09:29,250 --> 00:09:31,920 and print out the employee's name and salary. 207 00:09:31,920 --> 00:09:33,300 At the end of the function, 208 00:09:33,300 --> 00:09:35,790 this Box object goes out of scope, 209 00:09:35,790 --> 00:09:38,193 its drop function will be called, 210 00:09:39,870 --> 00:09:42,720 and the drop function will deallocate the employee 211 00:09:42,720 --> 00:09:43,650 on the heap. 212 00:09:43,650 --> 00:09:46,230 So the object that was allocated here, 213 00:09:46,230 --> 00:09:48,873 the pointer to it is owned by the Box. 214 00:09:49,950 --> 00:09:53,670 And when the Box that owns that pointer goes out of scope, 215 00:09:53,670 --> 00:09:58,350 then the object, the employee object is deallocated. 216 00:09:58,350 --> 00:10:02,013 It is deleted, memory is deleted on the heap. 217 00:10:04,530 --> 00:10:06,900 So I could run this example. 218 00:10:06,900 --> 00:10:08,280 I will run this example 219 00:10:08,280 --> 00:10:09,900 and I'm gonna see what errors might occur 220 00:10:09,900 --> 00:10:12,870 if I try to do things slightly incorrectly. 221 00:10:12,870 --> 00:10:15,033 So let's run it first. 222 00:10:17,310 --> 00:10:21,720 So the employee's created, I'd put into a Box, 223 00:10:21,720 --> 00:10:24,870 the Box was passed by value into the function. 224 00:10:24,870 --> 00:10:28,230 I printed out the employee's details, name and salary, 225 00:10:28,230 --> 00:10:30,120 the Box was dropped at this point, 226 00:10:30,120 --> 00:10:33,480 the employee object is deallocated, the Box object, 227 00:10:33,480 --> 00:10:35,940 I can't use the Box object up here. 228 00:10:35,940 --> 00:10:37,530 If I try to, 229 00:10:37,530 --> 00:10:40,440 then I'm going to get one of those familiar errors 230 00:10:40,440 --> 00:10:44,580 about trying to borrow an object after it's been moved away. 231 00:10:44,580 --> 00:10:46,953 Let's see the error message for the 101th time. 232 00:10:48,780 --> 00:10:52,323 So, yes indeed, so on line 17, 233 00:10:56,100 --> 00:10:58,680 yeah, it is line 17, 234 00:10:58,680 --> 00:11:02,400 on line 17, the value for Box step 235 00:11:02,400 --> 00:11:06,660 was moved into the function, so we don't own it anymore. 236 00:11:06,660 --> 00:11:09,360 So I'm trying to borrow the value 237 00:11:09,360 --> 00:11:12,480 of boxed_em after boxed_em has been moved, 238 00:11:12,480 --> 00:11:17,010 so that's a very common error, you can't use it then. 239 00:11:17,010 --> 00:11:18,510 I got one other thing I wanted to point out. 240 00:11:18,510 --> 00:11:23,190 I dunno if you noticed it, but Box is an object. 241 00:11:23,190 --> 00:11:24,600 It contains a pointer, 242 00:11:24,600 --> 00:11:28,653 and yet here I could just say box.name. 243 00:11:30,180 --> 00:11:31,860 We've seen this before. 244 00:11:31,860 --> 00:11:34,620 When you have references to an object 245 00:11:34,620 --> 00:11:37,890 and then you try to access a member inside that structure, 246 00:11:37,890 --> 00:11:40,080 automatically referencing takes place here 247 00:11:40,080 --> 00:11:41,730 when you access a member. 248 00:11:41,730 --> 00:11:44,460 So if I was gonna do this completely by the book, 249 00:11:44,460 --> 00:11:47,303 I'd have written it this way, I'd have said, 250 00:11:47,303 --> 00:11:49,870 *emp.name 251 00:11:50,851 --> 00:11:54,570 and *emp.salary, 252 00:11:54,570 --> 00:11:58,350 I was being pedantic because emp is a Box, 253 00:11:58,350 --> 00:12:00,690 so the start is the contents operator. 254 00:12:00,690 --> 00:12:03,030 Give me the contents of what you're pointing to, 255 00:12:03,030 --> 00:12:07,140 the employee, and then upon the employee, access the name 256 00:12:07,140 --> 00:12:08,550 and access the salary. 257 00:12:08,550 --> 00:12:10,710 So that is actually what's happening. 258 00:12:10,710 --> 00:12:15,540 But luckily for us, well, it's a happy bit of luck really. 259 00:12:15,540 --> 00:12:17,340 The compiler, when you have a Box, 260 00:12:17,340 --> 00:12:19,260 it automatically will dereference it 261 00:12:19,260 --> 00:12:22,920 when you access a member, when you access a member on a Box 262 00:12:22,920 --> 00:12:25,620 it'll actually dereference implicitly 263 00:12:25,620 --> 00:12:28,680 and access that member on the thing that you're pointing to. 264 00:12:28,680 --> 00:12:33,630 So it'll dereference the Box to give you the employee object 265 00:12:33,630 --> 00:12:36,750 and then access that, the salary inside it. 266 00:12:36,750 --> 00:12:38,760 So I can, just for fun, 267 00:12:38,760 --> 00:12:41,460 I'm going to use the star in one place, 268 00:12:41,460 --> 00:12:44,100 and I'm gonna leave out the star in another place 269 00:12:44,100 --> 00:12:46,983 just to show that both syntaxes actually do work. 270 00:12:49,950 --> 00:12:52,320 Yes, indeed, fantastic, so there we are. 271 00:12:52,320 --> 00:12:54,750 That's an example of the ownership of Box, 272 00:12:54,750 --> 00:12:59,010 Box is allocated on the stack, it doesn't implement copy. 273 00:12:59,010 --> 00:13:02,670 So if we pass a Box into a function, it's moved. 274 00:13:02,670 --> 00:13:04,533 And when the Box goes out of scope, 275 00:13:04,533 --> 00:13:07,530 it's drop function deallocates the thing 276 00:13:07,530 --> 00:13:08,430 that it's pointing to, 277 00:13:08,430 --> 00:13:10,350 it'll deallocate the item on the heap, 278 00:13:10,350 --> 00:13:12,100 which in this case is the employee.