1 00:00:06,608 --> 00:00:09,180 - In the previous demo we saw how to declare a variable 2 00:00:09,180 --> 00:00:11,340 with stack-based storage, 3 00:00:11,340 --> 00:00:13,380 so when you exited the function 4 00:00:13,380 --> 00:00:15,690 the variable automatically disappeared. 5 00:00:15,690 --> 00:00:18,690 In this section we're going to look at static storage. 6 00:00:18,690 --> 00:00:21,060 When you declare a variable with static storage, 7 00:00:21,060 --> 00:00:23,850 it remains allocated permanently, 8 00:00:23,850 --> 00:00:26,730 and it exists until the program terminates, okay? 9 00:00:26,730 --> 00:00:30,150 So you can use that to retain kind of like a global value 10 00:00:30,150 --> 00:00:31,170 would be an example. 11 00:00:31,170 --> 00:00:34,620 So in fact you can define static variables locally 12 00:00:34,620 --> 00:00:35,970 inside a function, 13 00:00:35,970 --> 00:00:38,820 it gets created the first time you call the function, 14 00:00:38,820 --> 00:00:42,540 and then it retains its value until the program terminates, 15 00:00:42,540 --> 00:00:45,690 but it's only visible within that function. 16 00:00:45,690 --> 00:00:48,570 Alternatively, you can declare a static globally, 17 00:00:48,570 --> 00:00:51,810 outside the function, so potentially you could then access 18 00:00:51,810 --> 00:00:54,660 that global variable in any function, 19 00:00:54,660 --> 00:00:57,960 and its value would be retained across the application. 20 00:00:57,960 --> 00:01:01,260 As a separate concept, we have the idea of mutability. 21 00:01:01,260 --> 00:01:03,810 Are you allowed to change the value or not? 22 00:01:03,810 --> 00:01:05,760 That's a separate consideration. 23 00:01:05,760 --> 00:01:08,520 What we're looking at here is the lifetime of the variable. 24 00:01:08,520 --> 00:01:10,620 A static variable lives forever 25 00:01:10,620 --> 00:01:12,840 from the point when it's created. 26 00:01:12,840 --> 00:01:15,933 So there is a difference between statics and consts. 27 00:01:16,800 --> 00:01:18,630 When you declare a static variable, 28 00:01:18,630 --> 00:01:20,400 it is actually a variable, 29 00:01:20,400 --> 00:01:22,290 it gets allocated in memory, 30 00:01:22,290 --> 00:01:25,410 it has a static lifetime, meaning it lives forever, 31 00:01:25,410 --> 00:01:26,790 it has an address, 32 00:01:26,790 --> 00:01:29,310 it physically occupies storage in memory, 33 00:01:29,310 --> 00:01:32,280 and you can take the address of it and you can refer to it. 34 00:01:32,280 --> 00:01:33,510 It could be mutable, 35 00:01:33,510 --> 00:01:35,910 you can declare a mutable static. 36 00:01:35,910 --> 00:01:38,400 You have to be a bit careful, but it is possible. 37 00:01:38,400 --> 00:01:41,130 You have to be careful with thread safety in that case. 38 00:01:41,130 --> 00:01:42,900 But it is possible to have a static 39 00:01:42,900 --> 00:01:45,600 whose value can be mutated. 40 00:01:45,600 --> 00:01:49,320 Consts on the other hand are not allocated in memory at all, 41 00:01:49,320 --> 00:01:51,240 they don't have an address, 42 00:01:51,240 --> 00:01:54,720 they just get substituted directly into your code on usage. 43 00:01:54,720 --> 00:01:56,192 So for example, 44 00:01:56,192 --> 00:01:59,580 if you declared a const called seconds in day, 45 00:01:59,580 --> 00:02:03,330 then the value would be 86,400. 46 00:02:03,330 --> 00:02:06,900 That value would be directly replaced in the code 47 00:02:06,900 --> 00:02:08,190 wherever you use the const. 48 00:02:08,190 --> 00:02:09,630 It's like a #define, 49 00:02:09,630 --> 00:02:11,880 it doesn't actually occupy any storage, 50 00:02:11,880 --> 00:02:14,223 it's just a compile-time constant. 51 00:02:15,240 --> 00:02:19,140 So back to statics, constants being fixed values, 52 00:02:19,140 --> 00:02:20,790 when you define a static variable, 53 00:02:20,790 --> 00:02:24,960 use the static keyword and specify a variable name. 54 00:02:24,960 --> 00:02:26,700 You have to use capital letters. 55 00:02:26,700 --> 00:02:29,220 Well, Rust will give you a warning if you don't. 56 00:02:29,220 --> 00:02:31,680 So static variables have capital letters 57 00:02:31,680 --> 00:02:33,080 to make them look different. 58 00:02:33,990 --> 00:02:36,000 You've got to specify the data type, 59 00:02:36,000 --> 00:02:37,710 type inference is not allowed, 60 00:02:37,710 --> 00:02:42,330 you have to specify the data type and a value, okay? 61 00:02:42,330 --> 00:02:47,330 Typically statics will be fixed, so not mutable, 62 00:02:48,570 --> 00:02:51,510 that's the general theme, it's easier, 63 00:02:51,510 --> 00:02:55,740 although you can have values which are evaluated at runtime, 64 00:02:55,740 --> 00:02:57,720 and we'll see both examples. 65 00:02:57,720 --> 00:02:58,890 Here's a simple example. 66 00:02:58,890 --> 00:03:02,850 I've got a local static variable inside some_func, 67 00:03:02,850 --> 00:03:05,670 the static keyword, here's a static variable, 68 00:03:05,670 --> 00:03:07,470 the name of the variable is MESSAGE, 69 00:03:08,370 --> 00:03:12,660 and it's of type, now this type here, ampersand str, 70 00:03:12,660 --> 00:03:15,510 technically that's a string slice. 71 00:03:15,510 --> 00:03:18,120 We'll have a look at string slices later on, 72 00:03:18,120 --> 00:03:21,330 just for now we'll just treat it as a string, 73 00:03:21,330 --> 00:03:24,750 and we've given it a compile-time string literal, okay? 74 00:03:24,750 --> 00:03:28,203 So this variable here will be initialized 75 00:03:28,203 --> 00:03:32,190 with a compile-time constant. 76 00:03:32,190 --> 00:03:35,130 And that's the easiest way of initializing the string. 77 00:03:35,130 --> 00:03:38,790 Just give it a fixed value, and the compiler knows 78 00:03:38,790 --> 00:03:40,440 what value to initialize it with. 79 00:03:41,910 --> 00:03:45,180 Right, it's also possible to have a static variable 80 00:03:45,180 --> 00:03:48,570 lazily initialized where it isn't a fixed value 81 00:03:48,570 --> 00:03:51,060 like hello, or the number 42, 82 00:03:51,060 --> 00:03:52,530 where the initial value is something 83 00:03:52,530 --> 00:03:55,200 that's gonna be computed at runtime. 84 00:03:55,200 --> 00:03:57,240 This is a bit more tricky. 85 00:03:57,240 --> 00:03:59,280 The simple approach that you might imagine 86 00:03:59,280 --> 00:04:01,950 to do the initialization doesn't actually work. 87 00:04:01,950 --> 00:04:02,970 Have a look at this example, 88 00:04:02,970 --> 00:04:04,440 it would give me a compiler error, 89 00:04:04,440 --> 00:04:06,500 and we'll see an example of the compiler error 90 00:04:06,500 --> 00:04:08,040 in a few minutes. 91 00:04:08,040 --> 00:04:12,060 So I've tried to anyway to declare a static local variable, 92 00:04:12,060 --> 00:04:17,060 TIMESTAMP, of type DateTime is a standard structure in Rust, 93 00:04:17,790 --> 00:04:19,320 and it's a generic, 94 00:04:19,320 --> 00:04:22,410 you've gotta give it a time zone parameter, okay? 95 00:04:22,410 --> 00:04:24,930 So which time zone are you working in? 96 00:04:24,930 --> 00:04:27,420 If you say DateTime, 97 00:04:27,420 --> 00:04:30,210 Utc is Universal Coordinated Time, 98 00:04:30,210 --> 00:04:33,930 it's kind of like Greenwich Mean Time, it's a time zone. 99 00:04:33,930 --> 00:04:35,640 So what I'm trying to do is I'm trying 100 00:04:35,640 --> 00:04:40,500 to initialize this variable at runtime 101 00:04:40,500 --> 00:04:42,063 with the current time. 102 00:04:43,080 --> 00:04:45,630 What I'm hoping to achieve is when the function gets called 103 00:04:45,630 --> 00:04:48,930 for the first time, it'll execute this function call, 104 00:04:48,930 --> 00:04:51,300 it'll determine the current date and time, 105 00:04:51,300 --> 00:04:54,570 and assign the value to this variable 106 00:04:54,570 --> 00:04:56,910 when the function is first called. 107 00:04:56,910 --> 00:04:59,730 And then it'll retain that value thereafter. 108 00:04:59,730 --> 00:05:03,450 This approach won't work because it's not thread safe. 109 00:05:03,450 --> 00:05:05,790 Thread safety is a really important, 110 00:05:05,790 --> 00:05:08,730 a big error in lots of traditional coding 111 00:05:08,730 --> 00:05:12,360 is when you have variables which are kind of accessed 112 00:05:12,360 --> 00:05:14,700 by multiple threads concurrently, 113 00:05:14,700 --> 00:05:17,160 and then you can kind of get thread disputes. 114 00:05:17,160 --> 00:05:19,740 One thread might be in the middle of changing the value 115 00:05:19,740 --> 00:05:22,410 while another thread is also changing the value. 116 00:05:22,410 --> 00:05:27,410 So Rust has very strict rules to preserve thread safety. 117 00:05:27,630 --> 00:05:29,310 It could have been the case that multiple threads 118 00:05:29,310 --> 00:05:31,530 will call in this function at the same time, 119 00:05:31,530 --> 00:05:32,940 and you might end up with a situation 120 00:05:32,940 --> 00:05:37,440 where both threads try to update this variable concurrently, 121 00:05:37,440 --> 00:05:39,123 and that's really not good. 122 00:05:40,110 --> 00:05:41,880 So you can't do it. 123 00:05:41,880 --> 00:05:44,140 If you have a static, you've gotta be a bit more careful 124 00:05:44,140 --> 00:05:46,950 about thread safety, you can't just assign it 125 00:05:46,950 --> 00:05:49,860 a computed value in case multiple threads were trying 126 00:05:49,860 --> 00:05:51,993 to do the same thing concurrently. 127 00:05:52,980 --> 00:05:56,730 So the way that you initialize a static variable 128 00:05:56,730 --> 00:06:00,810 to a runtime value is using something called a Lazy type. 129 00:06:00,810 --> 00:06:03,300 There's a structure type called Lazy. 130 00:06:03,300 --> 00:06:04,560 It's generic. 131 00:06:04,560 --> 00:06:07,782 So you can have a Lazy wrapper around a DateTime, 132 00:06:07,782 --> 00:06:10,440 or a Lazy wrapper around some kind of integer. 133 00:06:10,440 --> 00:06:13,080 Basically, it'll be a value that'll be computed 134 00:06:13,080 --> 00:06:14,740 in a thread-safe manner 135 00:06:16,020 --> 00:06:18,840 the first time you try to initialize it. 136 00:06:18,840 --> 00:06:20,370 Here is the syntax. 137 00:06:20,370 --> 00:06:23,070 So I need to explain quite a few things here. 138 00:06:23,070 --> 00:06:26,070 We'll come back to some of the details later on. 139 00:06:26,070 --> 00:06:28,650 So I'm trying to declare, this will actually work, 140 00:06:28,650 --> 00:06:31,533 I'm trying to declare a static variable called TIMESTAMP. 141 00:06:33,030 --> 00:06:36,330 Lazy is a wrapper, it's a wrapper type, 142 00:06:36,330 --> 00:06:39,360 and you specify what type of value it will contain. 143 00:06:39,360 --> 00:06:42,450 So you can imagine this is quite a good way to envisage it. 144 00:06:42,450 --> 00:06:46,470 You can imagine Lazy as being a wrapper 145 00:06:46,470 --> 00:06:49,590 which will initially not contain a value, 146 00:06:49,590 --> 00:06:53,940 but will evaluate the value inside it. 147 00:06:53,940 --> 00:06:56,940 It's like a box which will be evaluated 148 00:06:56,940 --> 00:06:58,830 in a thread-safe way. 149 00:06:58,830 --> 00:07:01,230 So the value inside the box, 150 00:07:01,230 --> 00:07:04,410 this kind of circle here is going to be a DateTime 151 00:07:04,410 --> 00:07:06,090 of Universal Coordinated Time. 152 00:07:06,090 --> 00:07:11,090 So it's a thread-safe wrapper around a DateTime object. 153 00:07:12,540 --> 00:07:15,360 And what you do is you initialize this Lazy variable, 154 00:07:15,360 --> 00:07:17,580 TIMESTAMP is a Lazy box. 155 00:07:17,580 --> 00:07:21,150 You initialize it like this, you say Lazy new, 156 00:07:21,150 --> 00:07:22,650 we're gonna discuss this syntax 157 00:07:22,650 --> 00:07:24,420 in a lot more detail later on. 158 00:07:24,420 --> 00:07:26,760 But just for now, 159 00:07:26,760 --> 00:07:30,360 structures can have effectively a static method, 160 00:07:30,360 --> 00:07:35,160 typically called new, to create a new instance of Lazy. 161 00:07:35,160 --> 00:07:38,130 So this code here will get evaluated 162 00:07:38,130 --> 00:07:42,030 the first time you actually need to use this variable. 163 00:07:42,030 --> 00:07:43,860 So the first time you use the variable here, 164 00:07:43,860 --> 00:07:46,080 I'll explain the star in a moment as well, 165 00:07:46,080 --> 00:07:48,660 the first time we try to use this Lazy box, 166 00:07:48,660 --> 00:07:52,170 it will be evaluated in a lazy fashion. 167 00:07:52,170 --> 00:07:56,433 This code here in green is called a closure. 168 00:07:58,320 --> 00:08:01,230 It's kind of similar to a lambda in other languages. 169 00:08:01,230 --> 00:08:03,240 It's like an anonymous function. 170 00:08:03,240 --> 00:08:06,960 The vertical bars represent the function parameters, 171 00:08:06,960 --> 00:08:08,610 there are no function parameters here, 172 00:08:08,610 --> 00:08:11,130 it's like a function that doesn't take any parameters, 173 00:08:11,130 --> 00:08:14,820 and it will evaluate this function and return that value. 174 00:08:14,820 --> 00:08:18,570 Whatever this lambda or this closure returns, 175 00:08:18,570 --> 00:08:22,320 the current date and time, that value will be placed 176 00:08:22,320 --> 00:08:26,130 inside the Lazy box at the point when you first evaluate it. 177 00:08:26,130 --> 00:08:28,650 Okay, so at that moment, at the point when you try 178 00:08:28,650 --> 00:08:31,710 to access the value inside the box, 179 00:08:31,710 --> 00:08:34,830 at that point this lambda, or this closure, 180 00:08:34,830 --> 00:08:39,600 will be executed just in time, and whatever it returns, 181 00:08:39,600 --> 00:08:42,240 that value will then be placed 182 00:08:42,240 --> 00:08:44,490 inside the Lazy box like that. 183 00:08:44,490 --> 00:08:47,330 And it invokes that lambda, or that closure, 184 00:08:47,330 --> 00:08:48,690 in a thread-safe manner. 185 00:08:48,690 --> 00:08:53,340 This thread-safe execution is guaranteed. 186 00:08:53,340 --> 00:08:57,420 So our Lazy box, TIMESTAMP is a Lazy variable, 187 00:08:57,420 --> 00:09:00,210 it has inside it a DateTime. 188 00:09:00,210 --> 00:09:04,770 In order to get the contents of that box, you say star, 189 00:09:04,770 --> 00:09:09,540 you deference the Lazy box to get the contents inside it, 190 00:09:09,540 --> 00:09:11,070 like so, okay? 191 00:09:11,070 --> 00:09:14,853 And it'll give you the value that you specified here. 192 00:09:15,900 --> 00:09:18,420 So this is quite tricky. 193 00:09:18,420 --> 00:09:20,070 I'll just summarize, 194 00:09:20,070 --> 00:09:22,560 and then we'll have a natural code example. 195 00:09:22,560 --> 00:09:26,460 I've got a static variable that I wanted to initialize 196 00:09:26,460 --> 00:09:28,230 to be a runtime value. 197 00:09:28,230 --> 00:09:30,240 I wanted to evaluate something at runtime 198 00:09:30,240 --> 00:09:33,300 as opposed to a simple number. 199 00:09:33,300 --> 00:09:35,283 So I wrap it in a Lazy box, 200 00:09:36,390 --> 00:09:40,770 I specify a closure in green to be invoked 201 00:09:40,770 --> 00:09:42,420 when first needed. 202 00:09:42,420 --> 00:09:45,000 The first time I need the value of the timestamp, 203 00:09:45,000 --> 00:09:48,330 only the first time, it will execute that code. 204 00:09:48,330 --> 00:09:49,890 Whatever that code returns, 205 00:09:49,890 --> 00:09:54,000 that value is placed inside the Lazy box, 206 00:09:54,000 --> 00:09:55,890 and my static has now been initialized, 207 00:09:55,890 --> 00:09:58,740 and I can use the star to get the contents 208 00:09:58,740 --> 00:10:01,080 inside that Lazy box. 209 00:10:01,080 --> 00:10:04,050 So you have to work quite hard in Rust 210 00:10:04,050 --> 00:10:07,380 to initialize a static variable at runtime, 211 00:10:07,380 --> 00:10:08,820 but at least it's thread safe. 212 00:10:08,820 --> 00:10:11,523 And this pattern, using the Lazy wrapper, 213 00:10:12,600 --> 00:10:14,490 you'll see this a lot. 214 00:10:14,490 --> 00:10:16,110 It's a shock the first time you see it, 215 00:10:16,110 --> 00:10:17,410 but you'll get used to it. 216 00:10:18,300 --> 00:10:21,630 So the Lazy object wraps a value safely, 217 00:10:21,630 --> 00:10:23,820 the value is initialized on first access, 218 00:10:23,820 --> 00:10:27,000 only the first time you try to access the value, 219 00:10:27,000 --> 00:10:31,080 only then, the first time, will that lambda be executed. 220 00:10:31,080 --> 00:10:33,750 I say lambda, I should say closure. 221 00:10:33,750 --> 00:10:36,000 Most languages would call that a lambda, 222 00:10:36,000 --> 00:10:37,200 but in Rust is called a closure. 223 00:10:37,200 --> 00:10:39,950 And we'll look at closures in a lot of detail later on. 224 00:10:41,070 --> 00:10:43,650 Okay, so access to the variable is thread safe. 225 00:10:43,650 --> 00:10:47,100 This code here is executed in a thread-safe manner, 226 00:10:47,100 --> 00:10:50,400 automatically guaranteed by Rust at the language level. 227 00:10:50,400 --> 00:10:52,080 Thread safety built in. 228 00:10:52,080 --> 00:10:54,273 So you can't go wrong, which is good.