1 00:00:05,239 --> 00:00:07,259 [music] 2 00:00:09,825 --> 00:00:11,845 [music] 3 00:00:15,599 --> 00:00:18,480 Welcome back everyone. I hope you are 4 00:00:18,480 --> 00:00:21,119 ready to hear our last speaker for the 5 00:00:21,119 --> 00:00:25,119 day in ballroom 2. So please give a warm 6 00:00:25,119 --> 00:00:28,165 welcome round of applause to Beno Rice. 7 00:00:28,165 --> 00:00:30,185 [applause] 8 00:00:34,160 --> 00:00:36,719 Thank you. Thank you. 9 00:00:36,719 --> 00:00:40,239 Right. So, um I'm sure I am alone in 10 00:00:40,239 --> 00:00:43,120 this room in being someone who is um 11 00:00:43,120 --> 00:00:44,800 deeply committed to overthinking 12 00:00:44,800 --> 00:00:47,440 everything. Um I'm sure there's nobody 13 00:00:47,440 --> 00:00:49,360 else here who does that. This is this is 14 00:00:49,360 --> 00:00:51,680 one of those talks that started through 15 00:00:51,680 --> 00:00:54,399 overthinking something a lot. Um, one 16 00:00:54,399 --> 00:00:57,120 thing I will say is some of you may have 17 00:00:57,120 --> 00:00:59,520 um noticed the title of the talk. Uh, 18 00:00:59,520 --> 00:01:02,160 this is not a talk about this state of 19 00:01:02,160 --> 00:01:05,360 exception. Um, this state of exception 20 00:01:05,360 --> 00:01:07,439 is an interesting one. It's not a fun 21 00:01:07,439 --> 00:01:09,600 read, but it is interesting. There is 22 00:01:09,600 --> 00:01:11,360 lots of material out there. I recommend 23 00:01:11,360 --> 00:01:13,439 learning about it when you're feeling in 24 00:01:13,439 --> 00:01:14,960 the right headsp space for it. But this 25 00:01:14,960 --> 00:01:17,759 is not what this is about. Um, this one 26 00:01:17,759 --> 00:01:20,880 mainly sort of started jelling um when 27 00:01:20,880 --> 00:01:24,159 this happened. Um, so about November 28 00:01:24,159 --> 00:01:25,759 last year, midway through November last 29 00:01:25,759 --> 00:01:30,320 year, Cloudflare had a fun time, um, 30 00:01:30,320 --> 00:01:35,840 from about 1120 UTC to about 1706 UTC, 31 00:01:35,840 --> 00:01:38,000 uh, they were returning a lot more 500s 32 00:01:38,000 --> 00:01:41,920 than you would have liked. Um, and you 33 00:01:41,920 --> 00:01:44,159 know, because they front, for better or 34 00:01:44,159 --> 00:01:47,200 for worse, a a very large proportion of 35 00:01:47,200 --> 00:01:50,479 the internet at the moment, um, it gets 36 00:01:50,479 --> 00:01:53,119 headlines. Um 37 00:01:53,119 --> 00:01:54,720 and 38 00:01:54,720 --> 00:01:56,560 the but the but the fun thing when these 39 00:01:56,560 --> 00:01:58,719 things happen is you know when US East 40 00:01:58,719 --> 00:02:00,560 one you know some part of AWS some part 41 00:02:00,560 --> 00:02:03,439 of Azure goes down we tend to get good 42 00:02:03,439 --> 00:02:05,840 writeups out of it and this was no 43 00:02:05,840 --> 00:02:08,080 exception we got a pretty good write up 44 00:02:08,080 --> 00:02:12,239 um and if we scroll a long way down 45 00:02:12,239 --> 00:02:16,080 through this writeup we get to this part 46 00:02:16,080 --> 00:02:18,959 where one of the things that was c that 47 00:02:18,959 --> 00:02:22,160 was contributing to this outage was that 48 00:02:22,160 --> 00:02:24,959 some rust code called the method unwrap 49 00:02:24,959 --> 00:02:29,360 on a result and this led to a panic. Now 50 00:02:29,360 --> 00:02:32,000 unwrap is a a fairly sort of simple 51 00:02:32,000 --> 00:02:35,360 function. You call it and if you have a 52 00:02:35,360 --> 00:02:37,680 result value that is not an error you 53 00:02:37,680 --> 00:02:40,000 get the value from it. But if it's an 54 00:02:40,000 --> 00:02:42,080 error then it panics and your process 55 00:02:42,080 --> 00:02:47,599 crashes. Um so this um this led to the 56 00:02:47,599 --> 00:02:49,599 uh instant expert brigade to start 57 00:02:49,599 --> 00:02:51,920 chiming in and saying that you know this 58 00:02:51,920 --> 00:02:54,480 is a sign that Rust is terrible. Um in 59 00:02:54,480 --> 00:02:58,000 particular um we have this from um guy 60 00:02:58,000 --> 00:03:00,160 called Brian Lunduke. Now if you've not 61 00:03:00,160 --> 00:03:03,680 heard of Brian Lunduke don't bother. Um 62 00:03:03,680 --> 00:03:06,800 he is let's he's a bit of a reactionary 63 00:03:06,800 --> 00:03:10,000 shall we say. And uh the illustrious Mr. 64 00:03:10,000 --> 00:03:13,840 Londuke's uh point of view here is that 65 00:03:13,840 --> 00:03:15,360 Cloudflare 66 00:03:15,360 --> 00:03:17,760 had rewritten this part of their system 67 00:03:17,760 --> 00:03:23,120 in Rust presumably because of woke. Um 68 00:03:23,120 --> 00:03:26,239 and thus this was the direct cause of 69 00:03:26,239 --> 00:03:32,000 their outage. Um, but you know [sighs] 70 00:03:32,000 --> 00:03:34,640 this this tied in with, you know, one of 71 00:03:34,640 --> 00:03:36,319 my fun little bits of overthinking that 72 00:03:36,319 --> 00:03:39,519 I like to do, which is 73 00:03:39,519 --> 00:03:41,680 what how do languages encourage us to 74 00:03:41,680 --> 00:03:43,040 think about error handling? Because it's 75 00:03:43,040 --> 00:03:44,879 really interesting to look at a language 76 00:03:44,879 --> 00:03:48,000 that you're working in and look at how 77 00:03:48,000 --> 00:03:50,000 is it encouraging you to think about 78 00:03:50,000 --> 00:03:52,799 certain things. Um, and error handling 79 00:03:52,799 --> 00:03:54,480 is an important one. I mean, we run into 80 00:03:54,480 --> 00:03:55,920 this a lot. So we're we're talking about 81 00:03:55,920 --> 00:03:57,439 this kind of situation here where your 82 00:03:57,439 --> 00:03:59,840 code is veering off the happy path and 83 00:03:59,840 --> 00:04:02,080 heading off somewhere else. What are we 84 00:04:02,080 --> 00:04:03,840 trying to do in this circumstance? What 85 00:04:03,840 --> 00:04:07,120 is what is the goal of error handling? 86 00:04:07,120 --> 00:04:09,360 Um and you know just to sort of focus 87 00:04:09,360 --> 00:04:12,720 things down a bit 88 00:04:12,720 --> 00:04:14,959 I'm mainly trying to think in terms of 89 00:04:14,959 --> 00:04:18,000 an operational thing. So we're talking 90 00:04:18,000 --> 00:04:20,400 about things like you know we all we 91 00:04:20,400 --> 00:04:22,639 want to do is maintain availability. We 92 00:04:22,639 --> 00:04:25,919 want to keep our services online. Um so 93 00:04:25,919 --> 00:04:28,400 by reacting to the error we might want 94 00:04:28,400 --> 00:04:30,320 to start uh shedding load towards 95 00:04:30,320 --> 00:04:32,960 different directions. We may need to 96 00:04:32,960 --> 00:04:35,520 spin up other things so on so forth. Um 97 00:04:35,520 --> 00:04:37,280 or at least you know get some telemetry 98 00:04:37,280 --> 00:04:38,800 into the right places so we can see that 99 00:04:38,800 --> 00:04:41,120 the errors are occurring and can react. 100 00:04:41,120 --> 00:04:42,400 But we also want to maintain 101 00:04:42,400 --> 00:04:45,040 consistency. Um we don't want to trash 102 00:04:45,040 --> 00:04:47,360 data like we don't want to get our ces 103 00:04:47,360 --> 00:04:49,040 mucked up. We don't want to we 104 00:04:49,040 --> 00:04:50,720 especially don't want to you know mess 105 00:04:50,720 --> 00:04:52,240 with all the database all the data at 106 00:04:52,240 --> 00:04:54,400 rest and all that kind of stuff. So what 107 00:04:54,400 --> 00:04:57,600 do we do when things go wrong and so 108 00:04:57,600 --> 00:04:59,280 through the next bit I am going to be 109 00:04:59,280 --> 00:05:01,759 using C as examples and the whole reason 110 00:05:01,759 --> 00:05:04,720 for that is because C is significantly 111 00:05:04,720 --> 00:05:07,600 less shall we say featureful in how it 112 00:05:07,600 --> 00:05:09,280 handles errors than everything else. And 113 00:05:09,280 --> 00:05:10,720 so I can sort of illustrate a few points 114 00:05:10,720 --> 00:05:12,960 with it. So what can we do when things 115 00:05:12,960 --> 00:05:16,240 go wrong? Option one nothing. We we 116 00:05:16,240 --> 00:05:18,400 don't have to do anything. I mean, 117 00:05:18,400 --> 00:05:20,479 especially in C, when something returns 118 00:05:20,479 --> 00:05:22,240 something, we can just we we we don't 119 00:05:22,240 --> 00:05:25,840 care. Um, so we can do something, we're 120 00:05:25,840 --> 00:05:27,919 not returning anything. We're type void. 121 00:05:27,919 --> 00:05:30,320 Um, we're not care, we only care that we 122 00:05:30,320 --> 00:05:31,759 get a thing and a widget out of these 123 00:05:31,759 --> 00:05:34,240 things. Everything else, don't mind. Um, 124 00:05:34,240 --> 00:05:35,759 this is generally not optimal. I 125 00:05:35,759 --> 00:05:38,000 wouldn't recommend this approach. 126 00:05:38,000 --> 00:05:39,600 Um, second thing we could do was we 127 00:05:39,600 --> 00:05:42,080 could tell someone. So, we can we can 128 00:05:42,080 --> 00:05:44,400 try to return like some bit of 129 00:05:44,400 --> 00:05:46,240 information that at least that the thing 130 00:05:46,240 --> 00:05:48,560 failed or whatever. So here we're we're 131 00:05:48,560 --> 00:05:50,720 returning in we're now returning an int 132 00:05:50,720 --> 00:05:52,320 because this is how you return errors in 133 00:05:52,320 --> 00:05:56,160 C. Um if you're not returning null. Um 134 00:05:56,160 --> 00:05:58,000 and so we've got our create thing and 135 00:05:58,000 --> 00:05:59,360 we're returning the the thing that comes 136 00:05:59,360 --> 00:06:00,560 out of that. Presumably another 137 00:06:00,560 --> 00:06:03,600 operation gives some information. That's 138 00:06:03,600 --> 00:06:05,199 still not really good though because 139 00:06:05,199 --> 00:06:07,280 we're not really cleaning anything up in 140 00:06:07,280 --> 00:06:09,759 here. We're not reacting to any of this. 141 00:06:09,759 --> 00:06:12,479 So you know we might need to actually 142 00:06:12,479 --> 00:06:14,960 like check that you know things happened 143 00:06:14,960 --> 00:06:18,080 there. So now we are returning the very 144 00:06:18,080 --> 00:06:21,360 informationrich value of minus1 145 00:06:21,360 --> 00:06:23,120 um presumably to say that things failed. 146 00:06:23,120 --> 00:06:26,800 Again this is very common C idiom. Um 147 00:06:26,800 --> 00:06:29,440 and you know as we progress further down 148 00:06:29,440 --> 00:06:30,960 there you know we again we're returning 149 00:06:30,960 --> 00:06:33,680 the stuff there. So this unfortunately 150 00:06:33,680 --> 00:06:35,280 doesn't give us a lot of context about 151 00:06:35,280 --> 00:06:37,840 why something failed. Um one approach 152 00:06:37,840 --> 00:06:40,000 that I've seen in C that is a quite you 153 00:06:40,000 --> 00:06:42,000 know not a terrible way to do things is 154 00:06:42,000 --> 00:06:43,680 you could have like a an error 155 00:06:43,680 --> 00:06:45,600 structure. So now we're now we're 156 00:06:45,600 --> 00:06:47,039 returning a pointer to an error 157 00:06:47,039 --> 00:06:50,400 structure. Um so we're we're declaring 158 00:06:50,400 --> 00:06:52,000 our error structure. We're doing some 159 00:06:52,000 --> 00:06:54,000 stuff. We create a thing so on so forth. 160 00:06:54,000 --> 00:06:56,479 So if if it's null then we're returning 161 00:06:56,479 --> 00:06:58,080 some function that presumably creates an 162 00:06:58,080 --> 00:06:59,520 error. So now we've got an error code. 163 00:06:59,520 --> 00:07:01,280 We've got some kind of in instructional 164 00:07:01,280 --> 00:07:03,120 that kind of stuff which is great. You 165 00:07:03,120 --> 00:07:04,479 know we continue down. We're doing this 166 00:07:04,479 --> 00:07:06,319 with the the widget as well. In this 167 00:07:06,319 --> 00:07:08,160 case the alloc widget thing takes a 168 00:07:08,160 --> 00:07:09,520 pointer to our error structure and fills 169 00:07:09,520 --> 00:07:11,120 it in for us. And so we just check that 170 00:07:11,120 --> 00:07:13,680 it's not null and return error. And then 171 00:07:13,680 --> 00:07:15,280 we can go down here. We're also passing 172 00:07:15,280 --> 00:07:16,960 error in there, returning error. But 173 00:07:16,960 --> 00:07:18,720 this also has problems because who saw 174 00:07:18,720 --> 00:07:21,759 the undefined behavior? 175 00:07:21,759 --> 00:07:24,319 Um, somebody thinks they did, I think, 176 00:07:24,319 --> 00:07:27,840 right up here. Um, we didn't initialize 177 00:07:27,840 --> 00:07:31,759 the error error variable. C does not 178 00:07:31,759 --> 00:07:34,800 have to make that null. Um, if you 179 00:07:34,800 --> 00:07:37,840 don't, then it's it might not be null, 180 00:07:37,840 --> 00:07:40,080 but it also it probably isn't useful. 181 00:07:40,080 --> 00:07:42,479 Um, ask me how I know we ran into that 182 00:07:42,479 --> 00:07:46,080 one. So again, you know, we we might 183 00:07:46,080 --> 00:07:47,919 want to clean up after ourselves as 184 00:07:47,919 --> 00:07:50,800 well. So, you know, in this case, we 185 00:07:50,800 --> 00:07:52,400 want to add some code here. So, we're 186 00:07:52,400 --> 00:07:54,879 we're now freeing our thing if our 187 00:07:54,879 --> 00:07:56,400 widget didn't allocate. So, we're 188 00:07:56,400 --> 00:08:00,960 actually sort of reacting to it. Um, and 189 00:08:00,960 --> 00:08:03,120 yeah, so and and then if our operation 190 00:08:03,120 --> 00:08:04,560 fails, then we're releasing things and 191 00:08:04,560 --> 00:08:06,879 freeing things, whatnot. Now, the 192 00:08:06,879 --> 00:08:08,000 problem with this is that you're 193 00:08:08,000 --> 00:08:10,479 intermingling a lot of your cleanup, 194 00:08:10,479 --> 00:08:13,199 your your reactive code to your happy 195 00:08:13,199 --> 00:08:14,960 path. It's all sort of spread out 196 00:08:14,960 --> 00:08:16,720 through that. And so, one of the ways 197 00:08:16,720 --> 00:08:19,520 I've seen to do this uh to to make this 198 00:08:19,520 --> 00:08:22,800 a bit tidier in C especially, uh, and I 199 00:08:22,800 --> 00:08:24,960 saw this a lot in FreeBSD code, it's 200 00:08:24,960 --> 00:08:26,479 used quite extensively through there, is 201 00:08:26,479 --> 00:08:29,759 to use the fact that C has go to. 202 00:08:29,759 --> 00:08:31,599 Um, 203 00:08:31,599 --> 00:08:34,399 for those who don't have that kind of 204 00:08:34,399 --> 00:08:36,399 knee-jerk eek reaction to go to, ask 205 00:08:36,399 --> 00:08:40,159 your parents. Um, [snorts] 206 00:08:40,159 --> 00:08:42,080 but [laughter] 207 00:08:42,080 --> 00:08:44,080 um, so yeah, what what we do in in this 208 00:08:44,080 --> 00:08:45,760 version of it, so what we've done now is 209 00:08:45,760 --> 00:08:47,279 that when we hit an error, we're just 210 00:08:47,279 --> 00:08:50,399 setting this return val variable and 211 00:08:50,399 --> 00:08:52,560 then saying go to error. Now, this also 212 00:08:52,560 --> 00:08:54,720 has problems too. Um, if you want to 213 00:08:54,720 --> 00:08:57,760 Google uh the the phrase Apple go to 214 00:08:57,760 --> 00:09:00,480 fail. Um, that was that was a fun one 215 00:09:00,480 --> 00:09:02,959 where they uh they they mucked up 216 00:09:02,959 --> 00:09:04,480 another fun bit of C which is you don't 217 00:09:04,480 --> 00:09:05,760 have to have braces after an if 218 00:09:05,760 --> 00:09:09,519 statement but if you anyway um so again 219 00:09:09,519 --> 00:09:11,200 you know so again we're just going to go 220 00:09:11,200 --> 00:09:12,880 to error so we don't have any cleanup 221 00:09:12,880 --> 00:09:15,360 code here because what we do here is 222 00:09:15,360 --> 00:09:17,519 after this return zero where we where 223 00:09:17,519 --> 00:09:20,959 we've succeeded here's our unhappy path 224 00:09:20,959 --> 00:09:22,959 and that that sort of tidies things up a 225 00:09:22,959 --> 00:09:24,399 bit and you can kind of see that if we 226 00:09:24,399 --> 00:09:27,120 kind of color code where we're using 227 00:09:27,120 --> 00:09:29,680 various things. You know, we can kind of 228 00:09:29,680 --> 00:09:32,000 see that we're in this version, our 229 00:09:32,000 --> 00:09:33,519 happy path, our error handling, our 230 00:09:33,519 --> 00:09:35,600 cleanup is all kind of inter 231 00:09:35,600 --> 00:09:37,120 intertwined, 232 00:09:37,120 --> 00:09:38,720 whereas, you know, once we start using 233 00:09:38,720 --> 00:09:40,560 the go-to, it all gets a little bit more 234 00:09:40,560 --> 00:09:43,279 cleaner. But this is still a problem 235 00:09:43,279 --> 00:09:45,360 here. Like the thing that's bad about 236 00:09:45,360 --> 00:09:47,440 this is that, you know, our error return 237 00:09:47,440 --> 00:09:50,240 values lack useful information. Like 238 00:09:50,240 --> 00:09:51,440 unless you're using that error 239 00:09:51,440 --> 00:09:52,560 structure, we don't get a lot of 240 00:09:52,560 --> 00:09:55,279 information about what failed where, you 241 00:09:55,279 --> 00:09:57,839 know, all that kind of stuff. And in C 242 00:09:57,839 --> 00:09:59,519 errors require handling at the immediate 243 00:09:59,519 --> 00:10:02,240 call site even when we're using goto. We 244 00:10:02,240 --> 00:10:04,320 still have to do that reactive bit right 245 00:10:04,320 --> 00:10:05,680 with the statement that we're looking 246 00:10:05,680 --> 00:10:09,120 at. So but you know most of the people 247 00:10:09,120 --> 00:10:10,720 in this room though I imagine don't use 248 00:10:10,720 --> 00:10:12,880 a lot of C. We use Python. And in Python 249 00:10:12,880 --> 00:10:14,320 the way that we do error handling is 250 00:10:14,320 --> 00:10:16,079 exceptions. 251 00:10:16,079 --> 00:10:18,079 You know exceptions are great. Um one of 252 00:10:18,079 --> 00:10:19,279 the interesting things that I stumbled 253 00:10:19,279 --> 00:10:21,600 across when researching this talk was 254 00:10:21,600 --> 00:10:24,720 that exceptions predate C by a 255 00:10:24,720 --> 00:10:26,399 significant margin. 256 00:10:26,399 --> 00:10:28,160 uh the first stuff that we see that 257 00:10:28,160 --> 00:10:30,720 looks like what we see as what we 258 00:10:30,720 --> 00:10:32,160 understand as exceptions today actually 259 00:10:32,160 --> 00:10:34,880 show up in list 1.5. 260 00:10:34,880 --> 00:10:39,920 Um and then C++ shows up in 1988 261 00:10:39,920 --> 00:10:43,200 gets exceptions in 1990 and then we get 262 00:10:43,200 --> 00:10:46,880 Python 0.9 in 1991. So exceptions have a 263 00:10:46,880 --> 00:10:48,720 longer history than you would think. And 264 00:10:48,720 --> 00:10:52,320 actually, uh, PL1 and Forran had a 265 00:10:52,320 --> 00:10:54,640 different mode of exception handling 266 00:10:54,640 --> 00:10:56,560 that looks a lot more like the way CPUs 267 00:10:56,560 --> 00:11:00,640 handle traps. Um, so yeah, just random 268 00:11:00,640 --> 00:11:02,160 bits of information that you come 269 00:11:02,160 --> 00:11:04,959 across. But yeah, you know, in Python, 270 00:11:04,959 --> 00:11:06,640 we don't necessarily have to put a lot 271 00:11:06,640 --> 00:11:08,480 of error handling in there because if 272 00:11:08,480 --> 00:11:09,839 anything happens in that, we're going to 273 00:11:09,839 --> 00:11:11,920 get a stack trace. 274 00:11:11,920 --> 00:11:13,519 And if you're, you know, if you, if 275 00:11:13,519 --> 00:11:15,519 you're using things like Sentry or other 276 00:11:15,519 --> 00:11:17,040 kinds of instrumentation, you're going 277 00:11:17,040 --> 00:11:18,320 to get that stack trace and all the 278 00:11:18,320 --> 00:11:20,000 information that goes with it. And an 279 00:11:20,000 --> 00:11:22,320 exception often has more information 280 00:11:22,320 --> 00:11:23,519 than, you know, well, definitely has 281 00:11:23,519 --> 00:11:27,200 more information than minus one. Um, 282 00:11:27,200 --> 00:11:29,760 and so, and if we if we look at that, 283 00:11:29,760 --> 00:11:30,959 you know, if we sort of dig through into 284 00:11:30,959 --> 00:11:32,480 that, our widget class presumably has 285 00:11:32,480 --> 00:11:34,720 some class method called allocate. So, 286 00:11:34,720 --> 00:11:35,920 and it's going to do something like 287 00:11:35,920 --> 00:11:37,040 this. You can see that we've actually 288 00:11:37,040 --> 00:11:39,760 got you presumably some kind of message 289 00:11:39,760 --> 00:11:41,279 and some context in there which is 290 00:11:41,279 --> 00:11:45,120 really handy. Um 291 00:11:45,120 --> 00:11:48,399 so um 292 00:11:48,399 --> 00:11:50,959 and then we can also do our own error 293 00:11:50,959 --> 00:11:53,920 handling within our operations. So we 294 00:11:53,920 --> 00:11:56,959 can we use try except you know do the 295 00:11:56,959 --> 00:11:59,200 exception comes up you know we can also 296 00:11:59,200 --> 00:12:00,959 put our cleanup handlings and that kind 297 00:12:00,959 --> 00:12:03,200 of stuff. It's you know much neater as 298 00:12:03,200 --> 00:12:04,560 we can see if we do the color coding 299 00:12:04,560 --> 00:12:06,240 trick again. And we can see that we have 300 00:12:06,240 --> 00:12:08,639 everything is nicely separated. So 301 00:12:08,639 --> 00:12:11,360 what's bad about exceptions? 302 00:12:11,360 --> 00:12:14,079 Well, the big one is that they can make 303 00:12:14,079 --> 00:12:16,399 following control flow more difficult. 304 00:12:16,399 --> 00:12:18,800 What I mean by that is that the the 305 00:12:18,800 --> 00:12:20,800 exceptions get can get raised where the 306 00:12:20,800 --> 00:12:23,920 error happens and handled where you want 307 00:12:23,920 --> 00:12:25,279 to handle them. But those can be 308 00:12:25,279 --> 00:12:26,880 different files. They can be different 309 00:12:26,880 --> 00:12:30,079 projects like it. And so it can be a bit 310 00:12:30,079 --> 00:12:32,399 hard to work out exactly where control 311 00:12:32,399 --> 00:12:34,560 flow is going to go once an exception is 312 00:12:34,560 --> 00:12:36,160 raised. 313 00:12:36,160 --> 00:12:38,240 But the other fun one, and this is a bit 314 00:12:38,240 --> 00:12:40,079 more subtle, is that exception handling 315 00:12:40,079 --> 00:12:44,160 requires runtime code. Um C doesn't have 316 00:12:44,160 --> 00:12:46,880 exceptions because C doesn't have much 317 00:12:46,880 --> 00:12:50,320 of what we would consider a runtime. C++ 318 00:12:50,320 --> 00:12:52,000 when it has exceptions because you can 319 00:12:52,000 --> 00:12:54,639 do C++ without them has to have a 320 00:12:54,639 --> 00:12:56,240 runtime library that does that because 321 00:12:56,240 --> 00:12:58,320 it has to work out how to unwind the 322 00:12:58,320 --> 00:13:00,959 stack the function call stack to where 323 00:13:00,959 --> 00:13:02,800 the exception handler is for that 324 00:13:02,800 --> 00:13:04,160 exception type so that it can move 325 00:13:04,160 --> 00:13:07,040 forward. Python obviously is effectively 326 00:13:07,040 --> 00:13:09,839 its own runtime and you same can be said 327 00:13:09,839 --> 00:13:12,560 by Java but looping back to where I came 328 00:13:12,560 --> 00:13:15,040 into this rust has no runtime. R the 329 00:13:15,040 --> 00:13:16,560 whole point of Rust is that it's it's 330 00:13:16,560 --> 00:13:19,120 meant to not do that. Rust is actually 331 00:13:19,120 --> 00:13:22,079 hilariously biased to compile time and 332 00:13:22,079 --> 00:13:23,600 doing everything it can within the 333 00:13:23,600 --> 00:13:26,480 compiler because one of the whole design 334 00:13:26,480 --> 00:13:29,120 goals of it was to be a replacement for 335 00:13:29,120 --> 00:13:31,600 C. And if you want to be a replacement 336 00:13:31,600 --> 00:13:34,000 for C, you can't rely on a runtime 337 00:13:34,000 --> 00:13:35,760 that's any more featured than what C 338 00:13:35,760 --> 00:13:38,720 has. And so as a result, Rust has no 339 00:13:38,720 --> 00:13:41,920 exceptions. What Rust does have is 340 00:13:41,920 --> 00:13:43,920 result types. 341 00:13:43,920 --> 00:13:48,399 So the Rust result type looks like this. 342 00:13:48,399 --> 00:13:50,880 Um I I literally copied and pasted this 343 00:13:50,880 --> 00:13:53,200 from the source code and then deleted 344 00:13:53,200 --> 00:13:56,000 some comments and directives about you 345 00:13:56,000 --> 00:13:57,760 know what versions things became stable 346 00:13:57,760 --> 00:14:01,440 in. But that is the uh the Rust result 347 00:14:01,440 --> 00:14:03,839 type. It is a public enumeration. So a 348 00:14:03,839 --> 00:14:07,199 Rust enumeration is more akin to a C 349 00:14:07,199 --> 00:14:10,079 union than it is anything else. um but 350 00:14:10,079 --> 00:14:11,360 with a whole bunch of compile time 351 00:14:11,360 --> 00:14:13,040 guarantees that you're not picking 352 00:14:13,040 --> 00:14:15,199 you're not treating one variant as 353 00:14:15,199 --> 00:14:18,320 another uh called result that is generic 354 00:14:18,320 --> 00:14:21,600 over two types T and E and then it has 355 00:14:21,600 --> 00:14:23,680 two variants one is called okay and 356 00:14:23,680 --> 00:14:26,079 contains a variable of type T and one 357 00:14:26,079 --> 00:14:27,519 and error which contains a variable of 358 00:14:27,519 --> 00:14:30,480 type E that is literally it 359 00:14:30,480 --> 00:14:33,360 but what this allows 360 00:14:33,360 --> 00:14:36,480 uh is so we can start doing this kind of 361 00:14:36,480 --> 00:14:38,365 construct here so 362 00:14:38,365 --> 00:14:39,199 [clears throat and cough] 363 00:14:39,199 --> 00:14:41,839 let is how you bind a a a v value to a 364 00:14:41,839 --> 00:14:44,800 variable. Match um should be familiar 365 00:14:44,800 --> 00:14:46,000 with anyone who's used you know 366 00:14:46,000 --> 00:14:49,279 relatively modern Python. Um so if what 367 00:14:49,279 --> 00:14:50,639 we're saying is that if the operation 368 00:14:50,639 --> 00:14:53,120 returns an okay with a value in it, we 369 00:14:53,120 --> 00:14:54,880 can we assign that value to the 370 00:14:54,880 --> 00:14:57,519 variable. Otherwise is if it's an error, 371 00:14:57,519 --> 00:15:02,160 we do this construct down here. Uh so 372 00:15:02,160 --> 00:15:05,120 from is a is a trait which is another 373 00:15:05,120 --> 00:15:07,760 aspect of the rust type system. In this 374 00:15:07,760 --> 00:15:09,680 case it's a trait. So traits can be 375 00:15:09,680 --> 00:15:12,000 defined on types 376 00:15:12,000 --> 00:15:15,519 um that we can define onto a type. So 377 00:15:15,519 --> 00:15:17,600 that's the self down there that will 378 00:15:17,600 --> 00:15:20,480 convert a value of type t to that to 379 00:15:20,480 --> 00:15:23,120 this type. This is also pretty much 380 00:15:23,120 --> 00:15:25,519 literally copied from the source code. 381 00:15:25,519 --> 00:15:27,279 But what we get back to here is what 382 00:15:27,279 --> 00:15:29,839 that means is we can convert the error 383 00:15:29,839 --> 00:15:33,440 into an error type that the the method 384 00:15:33,440 --> 00:15:35,839 itself can actually return. 385 00:15:35,839 --> 00:15:38,000 But all of this is just put here to say 386 00:15:38,000 --> 00:15:39,199 that you don't actually ever really 387 00:15:39,199 --> 00:15:40,880 write that a lot in Python. What you 388 00:15:40,880 --> 00:15:43,199 write is this 389 00:15:43,199 --> 00:15:45,040 because the question mark operator at 390 00:15:45,040 --> 00:15:48,240 the end is syntactic sugar that expands 391 00:15:48,240 --> 00:15:51,199 to the other bit. It's it's a really 392 00:15:51,199 --> 00:15:53,600 sort of easy way of doing that kind of 393 00:15:53,600 --> 00:15:56,880 uh short circuit error handling for if a 394 00:15:56,880 --> 00:15:58,480 an operation that you're depending on 395 00:15:58,480 --> 00:16:02,079 fails just return the error upwards. And 396 00:16:02,079 --> 00:16:03,839 so we can start writing, you know, if we 397 00:16:03,839 --> 00:16:05,680 were writing our sum operation in Rust, 398 00:16:05,680 --> 00:16:07,759 we could look a bit like this. We're 399 00:16:07,759 --> 00:16:11,279 we're now returning a result over what 400 00:16:11,279 --> 00:16:13,600 what is effectively a null uh return 401 00:16:13,600 --> 00:16:18,560 value and some error type. Um when we 402 00:16:18,560 --> 00:16:20,800 call thing new, we're using the question 403 00:16:20,800 --> 00:16:22,880 mark operator to just return up if it 404 00:16:22,880 --> 00:16:27,120 fails. And then for uh the widget alloc 405 00:16:27,120 --> 00:16:30,000 u call we're using the or else which is 406 00:16:30,000 --> 00:16:32,720 a a method on result that lets you pass 407 00:16:32,720 --> 00:16:34,399 in a closure that lets you do stuff. So 408 00:16:34,399 --> 00:16:35,920 when we when we hit that then we're 409 00:16:35,920 --> 00:16:37,920 returning we're freeing the thing that 410 00:16:37,920 --> 00:16:39,519 we allocated and then returning the 411 00:16:39,519 --> 00:16:43,839 error upwards and so on so forth. Um and 412 00:16:43,839 --> 00:16:46,320 so if the result is is is error then we 413 00:16:46,320 --> 00:16:49,199 can when then we can uh call out various 414 00:16:49,199 --> 00:16:52,639 cleanup things and even that you can get 415 00:16:52,639 --> 00:16:55,120 around a bit in rust because uh rust 416 00:16:55,120 --> 00:16:58,000 also has another trait called drop 417 00:16:58,000 --> 00:17:01,360 and drop will handle cleaning up objects 418 00:17:01,360 --> 00:17:03,040 that have moved out of scope for you 419 00:17:03,040 --> 00:17:05,600 because again rust is heavily biased 420 00:17:05,600 --> 00:17:08,319 towards compile time analysis of what 421 00:17:08,319 --> 00:17:10,959 your code's doing. And so it re it knows 422 00:17:10,959 --> 00:17:12,559 when you're not going to be using that 423 00:17:12,559 --> 00:17:14,319 variable anymore and will clean it up 424 00:17:14,319 --> 00:17:17,559 for you. 425 00:17:17,679 --> 00:17:20,000 And so that would allow us to get our 426 00:17:20,000 --> 00:17:23,679 code down to something like this. 427 00:17:23,679 --> 00:17:26,160 So having gone through all that and 428 00:17:26,160 --> 00:17:28,799 looping back to where we started, was 429 00:17:28,799 --> 00:17:31,280 calling unwrap bad? 430 00:17:31,280 --> 00:17:35,520 So just to refresh, unwrap um when we 431 00:17:35,520 --> 00:17:39,200 call it is um unlike the question mark 432 00:17:39,200 --> 00:17:41,600 operator which will return your error 433 00:17:41,600 --> 00:17:45,120 value if you if it was an error. What 434 00:17:45,120 --> 00:17:47,440 unwrap does is it is it gives you the 435 00:17:47,440 --> 00:17:50,320 the value inside the result if it's if 436 00:17:50,320 --> 00:17:53,120 it's the okay variant. But if it's the 437 00:17:53,120 --> 00:17:55,520 error, it will panic. 438 00:17:55,520 --> 00:17:58,080 Um, so if we actually scroll back, if we 439 00:17:58,080 --> 00:18:00,799 actually scroll back up this bit, 440 00:18:00,799 --> 00:18:02,640 this is about this was running in a 441 00:18:02,640 --> 00:18:05,039 pre-allocated a memory, an environment 442 00:18:05,039 --> 00:18:06,480 where they had pre-allocated a bunch of 443 00:18:06,480 --> 00:18:10,000 memory, but then the code had been given 444 00:18:10,000 --> 00:18:12,480 a lot more data than it expected and it 445 00:18:12,480 --> 00:18:14,400 exhausted its available memory and was 446 00:18:14,400 --> 00:18:16,960 not able to allocate more. 447 00:18:16,960 --> 00:18:18,640 I'm not sure any other language really 448 00:18:18,640 --> 00:18:20,880 would have been able to deal with that. 449 00:18:20,880 --> 00:18:23,360 So, you know, [snorts] I I think that 450 00:18:23,360 --> 00:18:25,200 calling unwrap there was actually not 451 00:18:25,200 --> 00:18:27,280 the, you know, not the worst thing to 452 00:18:27,280 --> 00:18:29,039 do. The only thing that I would do if I 453 00:18:29,039 --> 00:18:31,600 was reviewing that code is maybe call 454 00:18:31,600 --> 00:18:34,000 expect instead. 455 00:18:34,000 --> 00:18:36,799 So, you know, um, just to give an 456 00:18:36,799 --> 00:18:38,799 example, unwrap, you know, this is a 457 00:18:38,799 --> 00:18:41,919 very like contorted example, but you 458 00:18:41,919 --> 00:18:43,919 know, if we call unwrap here, we get a 459 00:18:43,919 --> 00:18:45,200 result like this where it says you just 460 00:18:45,200 --> 00:18:48,160 called unwrap on an error value. Um 461 00:18:48,160 --> 00:18:51,120 whereas expect allows you to say what 462 00:18:51,120 --> 00:18:52,720 you were doing. It allows you to add 463 00:18:52,720 --> 00:18:54,160 context to it. And so that would give 464 00:18:54,160 --> 00:18:58,559 you an error like this. Um and so you 465 00:18:58,559 --> 00:19:00,960 maybe call expect instead. And but 466 00:19:00,960 --> 00:19:04,960 that's a minor quibble at best. Um and 467 00:19:04,960 --> 00:19:07,200 the thing is, you know, if only when 468 00:19:07,200 --> 00:19:09,919 Brian Lunduke was waffling on about uh 469 00:19:09,919 --> 00:19:11,360 Rust being terrible, he'd actually 470 00:19:11,360 --> 00:19:15,200 looked at that. Oh. 471 00:19:15,200 --> 00:19:18,108 Mhm. [sighs and gasps] 472 00:19:18,240 --> 00:19:21,600 Anyway, we can ignore him now. So, the 473 00:19:21,600 --> 00:19:25,120 thing I like is that Rust's result type 474 00:19:25,120 --> 00:19:27,440 forces you to acknowledge the 475 00:19:27,440 --> 00:19:30,400 possibility of error. And um I am just 476 00:19:30,400 --> 00:19:32,799 going to, you know, forewarn here. I'm 477 00:19:32,799 --> 00:19:34,720 going to be taking shots at another 478 00:19:34,720 --> 00:19:37,120 language here. This is not meant to be 479 00:19:37,120 --> 00:19:40,240 mockery or or contempt as such. This is 480 00:19:40,240 --> 00:19:43,360 technical critique, shall we say. Um, 481 00:19:43,360 --> 00:19:45,120 rust result type forces you to 482 00:19:45,120 --> 00:19:46,799 acknowledge that error is a possibility. 483 00:19:46,799 --> 00:19:48,480 When we look at the, you know, sort of 484 00:19:48,480 --> 00:19:51,440 rust type code, we are not allowed to 485 00:19:51,440 --> 00:19:55,280 get at the the the the value that we 486 00:19:55,280 --> 00:19:57,760 want inside the result without either 487 00:19:57,760 --> 00:20:00,880 calling something like question mark to 488 00:20:00,880 --> 00:20:02,799 say, you know, I either want to return 489 00:20:02,799 --> 00:20:04,640 an error if this is an error or I want 490 00:20:04,640 --> 00:20:06,480 the value if it's good or calling 491 00:20:06,480 --> 00:20:09,280 something like unwrap. We have to we 492 00:20:09,280 --> 00:20:10,799 have to acknow we have to choose our 493 00:20:10,799 --> 00:20:12,559 poison basically. Are we going to return 494 00:20:12,559 --> 00:20:14,640 this error up or are we going to panic 495 00:20:14,640 --> 00:20:16,559 if it fails? 496 00:20:16,559 --> 00:20:19,720 And and 497 00:20:20,559 --> 00:20:24,320 why do we not learn the lessons about 498 00:20:24,320 --> 00:20:26,720 what made C bad? 499 00:20:26,720 --> 00:20:29,679 Every time I look at Go code and I see 500 00:20:29,679 --> 00:20:32,799 if error not equal nil, I die a little 501 00:20:32,799 --> 00:20:34,640 inside 502 00:20:34,640 --> 00:20:38,080 because we learned the lesson 503 00:20:38,080 --> 00:20:40,400 of somewhat because we have this 504 00:20:40,400 --> 00:20:42,640 multiple return thing where we can 505 00:20:42,640 --> 00:20:45,679 return an error. But as soon as I have 506 00:20:45,679 --> 00:20:47,039 to check whether it's a nil and do 507 00:20:47,039 --> 00:20:48,159 something with it, that makes it feel 508 00:20:48,159 --> 00:20:50,480 like it's an option. 509 00:20:50,480 --> 00:20:53,760 It makes it feel like the the error is 510 00:20:53,760 --> 00:20:55,760 not necessarily something I have to deal 511 00:20:55,760 --> 00:20:57,760 with. I can just like you know I don't 512 00:20:57,760 --> 00:21:00,400 know if error whatever and so you know 513 00:21:00,400 --> 00:21:03,760 loops me back to how languages encourage 514 00:21:03,760 --> 00:21:06,880 us to think about error handling like 515 00:21:06,880 --> 00:21:09,520 how what what mindset does it want us to 516 00:21:09,520 --> 00:21:11,120 be in when we're deal dealing with this 517 00:21:11,120 --> 00:21:13,679 stuff and so yeah that's the end of me 518 00:21:13,679 --> 00:21:19,280 ranting about go anyway um so looking at 519 00:21:19,280 --> 00:21:22,880 this failure um that cloud play went 520 00:21:22,880 --> 00:21:25,200 through it was really a complex like it 521 00:21:25,200 --> 00:21:27,440 was a series of things. It was a change 522 00:21:27,440 --> 00:21:30,159 in behavior for a database query that 523 00:21:30,159 --> 00:21:31,840 led to a generated data file that was 524 00:21:31,840 --> 00:21:33,280 more than double the size that was 525 00:21:33,280 --> 00:21:36,000 expected that the process attempted to 526 00:21:36,000 --> 00:21:38,080 pass exceeded its memory limit and 527 00:21:38,080 --> 00:21:40,720 crashed which led to a lot of 500 528 00:21:40,720 --> 00:21:44,880 responses. And you know this is it's not 529 00:21:44,880 --> 00:21:46,720 just a code problem. This is a systems 530 00:21:46,720 --> 00:21:48,559 problem. 531 00:21:48,559 --> 00:21:50,480 And 532 00:21:50,480 --> 00:21:52,559 one of the fun things that I came 533 00:21:52,559 --> 00:21:53,679 another one of the fun things I came 534 00:21:53,679 --> 00:21:54,720 across when I was looking through this 535 00:21:54,720 --> 00:21:56,960 was this paper here called how complex 536 00:21:56,960 --> 00:22:00,480 systems fail. Um, what was hilarious was 537 00:22:00,480 --> 00:22:02,159 when I first delivered this talk, the 538 00:22:02,159 --> 00:22:04,559 person who set up this website that it's 539 00:22:04,559 --> 00:22:07,600 hosted at was in the audience, which was 540 00:22:07,600 --> 00:22:09,520 rather fun, which wasn't Richard Cook, 541 00:22:09,520 --> 00:22:11,200 it was someone else. But yeah, um, this 542 00:22:11,200 --> 00:22:13,200 has this is a fairly short piece. It's 543 00:22:13,200 --> 00:22:15,760 really worth a read. But, you know, we 544 00:22:15,760 --> 00:22:17,520 start with complex systems are 545 00:22:17,520 --> 00:22:19,919 intrinsically hazardous systems. But the 546 00:22:19,919 --> 00:22:21,360 the bits that I found really interesting 547 00:22:21,360 --> 00:22:24,000 was cat catastrophe requires multiple 548 00:22:24,000 --> 00:22:25,760 failures. Single point failures are not 549 00:22:25,760 --> 00:22:27,919 enough. We're generally pretty good at 550 00:22:27,919 --> 00:22:30,559 working out and gaming out where the 551 00:22:30,559 --> 00:22:33,360 obvious failure points in a system are. 552 00:22:33,360 --> 00:22:34,640 It's always the interesting 553 00:22:34,640 --> 00:22:36,480 intersections of multiple ones that 554 00:22:36,480 --> 00:22:40,320 really get you. Um and then the other 555 00:22:40,320 --> 00:22:43,600 part is human practitioners are the 556 00:22:43,600 --> 00:22:47,039 adaptable element of complex systems. Um 557 00:22:47,039 --> 00:22:48,480 how does it feel to be in the loop 558 00:22:48,480 --> 00:22:50,159 folks? 559 00:22:50,159 --> 00:22:53,520 Um but the other thing is that we are a 560 00:22:53,520 --> 00:22:56,880 lot better at especially once we have an 561 00:22:56,880 --> 00:22:59,200 understanding of a system. Humans are 562 00:22:59,200 --> 00:23:00,559 really good at just being able to go 563 00:23:00,559 --> 00:23:03,679 hang on this feels like that. 564 00:23:03,679 --> 00:23:07,039 Um there was a a fun there was another 565 00:23:07,039 --> 00:23:09,760 failure around the same time at Blue Sky 566 00:23:09,760 --> 00:23:13,200 where they once they d they had to first 567 00:23:13,200 --> 00:23:15,120 understand the problem once they um 568 00:23:15,120 --> 00:23:16,880 diagnosed it they had came up with this 569 00:23:16,880 --> 00:23:19,919 great um like hilariously Barack way of 570 00:23:19,919 --> 00:23:21,200 fixing it because they had to basically 571 00:23:21,200 --> 00:23:23,520 bind to multiple loop back interfaces to 572 00:23:23,520 --> 00:23:25,280 get enough local ports for things to be 573 00:23:25,280 --> 00:23:27,120 able to talk to each other. And being 574 00:23:27,120 --> 00:23:29,760 able to reason through that kind of like 575 00:23:29,760 --> 00:23:32,320 hard left turn in how you fix something 576 00:23:32,320 --> 00:23:36,400 is something that I think you know it's 577 00:23:36,400 --> 00:23:39,039 more likely that humans hit on that kind 578 00:23:39,039 --> 00:23:41,840 of solution than 579 00:23:41,840 --> 00:23:46,080 other tools shall we say. Um, but when I 580 00:23:46,080 --> 00:23:47,679 was reading that write up, there was 581 00:23:47,679 --> 00:23:49,919 another sort of commentary on that write 582 00:23:49,919 --> 00:23:52,080 up where the person had said that they'd 583 00:23:52,080 --> 00:23:53,520 been in environments where there were 584 00:23:53,520 --> 00:23:55,200 failures going on and someone had walked 585 00:23:55,200 --> 00:23:56,960 in, looked at a graph and gone, it's 586 00:23:56,960 --> 00:23:59,440 this. 587 00:23:59,440 --> 00:24:02,400 And that level of understanding of 588 00:24:02,400 --> 00:24:06,480 systems is what I worry is at risk when 589 00:24:06,480 --> 00:24:09,120 we are outsourcing a lot of our 590 00:24:09,120 --> 00:24:11,200 understanding to other things. Uh 591 00:24:11,200 --> 00:24:14,159 there's another paper that um uh Chris 592 00:24:14,159 --> 00:24:17,440 Nogabau was uh talking a lot about a 593 00:24:17,440 --> 00:24:19,200 while ago which is this one programming 594 00:24:19,200 --> 00:24:22,480 is theory building by Peter Na um uh 595 00:24:22,480 --> 00:24:25,440 that link goes to an OCR text version of 596 00:24:25,440 --> 00:24:27,440 it that Chris put up um because he 597 00:24:27,440 --> 00:24:30,960 couldn't find one um which talks about 598 00:24:30,960 --> 00:24:35,840 how the end goal of writing software is 599 00:24:35,840 --> 00:24:39,120 an understanding of the system at least 600 00:24:39,120 --> 00:24:40,880 as much as it is the OD that's coming 601 00:24:40,880 --> 00:24:43,200 out of the process and that that 602 00:24:43,200 --> 00:24:46,240 understanding is 603 00:24:46,240 --> 00:24:49,360 um is kind of tied to the people that 604 00:24:49,360 --> 00:24:51,440 developed it and is very hard to 605 00:24:51,440 --> 00:24:53,279 transfer. 606 00:24:53,279 --> 00:24:57,039 Um and it really just drove home to me 607 00:24:57,039 --> 00:24:59,279 that it I I really feel that you can't 608 00:24:59,279 --> 00:25:02,159 repair a system unless you understand 609 00:25:02,159 --> 00:25:06,720 it. and how quickly you can deploy that 610 00:25:06,720 --> 00:25:09,120 understanding is really going to be key 611 00:25:09,120 --> 00:25:10,880 when you're faced with a situation like 612 00:25:10,880 --> 00:25:16,000 this. So with that, um, thank you very 613 00:25:16,000 --> 00:25:19,017 much. [applause] 614 00:25:22,237 --> 00:25:24,257 [applause] 615 00:25:25,360 --> 00:25:28,559 My voice held out. Yay. 616 00:25:28,559 --> 00:25:31,039 But we'll be happy. I'll be happy to 617 00:25:31,039 --> 00:25:33,840 take some questions during afternoon 618 00:25:33,840 --> 00:25:34,559 tea. 619 00:25:34,559 --> 00:25:35,840 Yes. Come find me outside. 620 00:25:35,840 --> 00:25:38,799 Yes. So, thank you so much once again. 621 00:25:38,799 --> 00:25:41,232 Another round of applause, please. 622 00:25:41,232 --> 00:25:43,252 [applause] 623 00:25:45,279 --> 00:25:48,799 And on behalf of Pyon AU26, another for 624 00:25:48,799 --> 00:25:52,367 the collection. Thank you very much. 625 00:25:52,367 --> 00:25:56,039 [applause] Thank you.