Should we have a Rust 2021 edition?
Klabnik, Steve
In 2018, Rust adopted an "edition" system. This lets Rust evolve in ways that feel like breaking changes but are opt-in only, and that do not disturb the open-source ecosystem. Given that Rust 2018 happened three years after the initial 2015 release of Rust, this has everyone wondering: is 2021 the year we have our next edition? In this talk, Steve lays out his own feelings on this question, as well as talks about the history of the edition system, how it works, and what it might look like in 2021.
 All right. Hey everybody, I'm Steve. Thanks for coming to my talk. This talk is titled Should We Have A 2021 Edition? And today is the 27th. So for those of you who don't know, I am on the core team of Rust. I previously led the documentation team and I wrote the Rust programming language, which is the introductory book on Rust that comes with Rust itself. Two other things, though, that you may or may not know, I figured I would mention before getting to the meat of this talk. I recently got a new job at a company called Oxide Computer Company. We're building new server computers for people to use. And we're doing like everything in Rust. So these days, I'm like writing embedded Rust and it's awesome. And we've had an embedded working group working on it for a while. And I appreciated the work in the abstract sense. But now that I'm actually doing the work as my job, it's fantastic. So that's pretty cool. And we are also hiring. So if you are interested in a job where you will write a lot of Rust, you may want to check that out. Finally, I have started actually working on open source Rust streaming stuff. So I'm doing my Twitch now. So if you want to watch me program on Tuesdays, that's the thing I'm doing. Okay. Anyway, enough about me. You want to hear about additions. So today, we're going to kind of cover these like three major points in this order. So the first one is what exactly are additions? I want to make sure that we're on the same page about the details because the details do actually matter and matter a lot here. Secondly, we've already done sort of one edition release, which is Rust 2018. And so I kind of want to take a look at that and like kind of how it went and some like thoughts, you know, after some time has passed. So it's kind of like a little bit of a case study, maybe a little bit of retrospective, you know, let's like talk about Rust 2018. And then finally, like, what should we actually do? And this is phrased as should we have Rust 2021? That's kind of like a big thing people have been talking about lately. I want to sort of emphasize, especially with both of these second sections, that this is like my personal opinion, while I am on the core team, I am only one person. And, you know, this is all phrased as like, should we because technically nothing has been decided. So while I do have my own opinions on this, feel free to disagree and just like, you know, this is this is me saying this. So take that as far as that goes. All right, so first up this first section. What even are additions anyway? If you don't know at all, thank you for coming my talk, even though you don't know the subject. This is exactly why I included this section. But even if you do, there's some details that maybe some people don't always think about. So I want to talk about a lot of those details. It's kind of two aspects to additions that I think are really important. And the first one is the sort of social aspect of Rust. So in addition is kind of this time point in time where we say, hey, Rust is significantly different now that it was in the past. And, you know, here's kind of like why. So Rust 1.0 came out in 2015. Rust 2018 was the first edition sort of release that came out in 2018. And we sort of said like, hey, you know, Rust has changed a lot in the last three years. You know, let's talk about all the stuff we've accomplished and add in some other things. And so that's like largely a social thing. So this is a way to sort of reflect on the longer term progress of the language and the project as a whole. Because we release every six weeks, that is like a really great thing for a lot of reasons. But it's really hard to like remember how much work we've done. Releases come out all the time and they're in small little chunks. And so it can be really, really easy to forget like just how far long things came. Half the time I forget that it's been like almost five years since Rust 1.0. Because when things are happening at such a rapid pace, it's really easy to, you know, lose track of like how far we've come. And so that's like really important. A second one is a point on like why additions matter are that there are a way to get new users into Rust. So this sort of is kind of similar to the first point, but a little bit different. Basically, you know, because we release every six weeks, there's a lot of people who don't pay attention to Rust releases because they see them so often and they have not that much in them. And so they're kind of like, you know, hey, you know, I, a new Rust release happens, I don't care. With the languages that release like once a year or once every couple of years, it's a really big deal. And so a lot of people will like hear about like, you know, oh, there's a new version of C++ out or there's a new version of Ruby out or the new C sharp has these cool new things in it. And that's a way for people who don't currently program in the language to sort of like it signals to them, hey, you know, I should check this out. Maybe, you know, I looked at C sharp 3.0, and I didn't really like what was going on. So I didn't use it. Maybe C sharp four, like time for me to check in again, maybe I want to start programming in it. And so it's kind of a nice way to signal to people outside of the Rust world as well, that you know, hey, a lot has gone on, and maybe if you didn't use Rust in the past, you would want to use it again. And then finally, like kind of for actually like development of Rust, sort of like a nice like rallying cry, I guess, basically, like, you know, not only is about reflecting on what we've done, but also if there's sort of big things we want to do, it's nice to build a point in the near future and say, like, you know, hey, it's 2020. Now, we want to do a Rust 2021. And we want to like get people excited. So let's start working on some projects that will like really generate that excitement. And there's some like back and forth here. And we're going to talk about all those details in a minute. But it can be a really great way to sort of get everybody excited about the future of Rust. Because, you know, we like need those check in kind of points, I think. But also additions are not purely a tech social mechanism, they're also a technical mechanism. And this this really matters. And so on a technical level, additions are a way to kind of make breaking changes to the Rust language, without actually making breaking changes. And so how this kind of works on a technical level is that additions are opt in. So you say what addition your code is in. And if you don't update that, then you don't update, you know, stuff. So if new things are added in a way that's like technically breaking, and it doesn't break you, because if you didn't opt in to the new changes, then your code still works forever. So this is like very different than, you know, Python two to Python three, for example, where, you know, you can't run your code kind of like together. And, you know, similar kind of things like that. So we can like make it a way to opt in to breaking changes. And that's really, really important for compatibility reasons. And then finally, additions are not allowed to change everything about Rust. This is a technical problem as much as there's a social problem. And there's some interplay back and forth between the two. But basically, like, major, major changes are not actually allowed. So some kinds of breaking changes are fine. But there are some kinds of changes that cannot be made in the addition mechanism. And that's due to the technical details of how all of this works. It does also kind of a social thing in the sense that it's also useful for humans, like, if tomorrow, like say Rust 2021 was going to be like garbage collected and use significant white spaces that occurly races, it would effectively be a whole different language. And that would make it a really big challenge for people to update to. But because we can only make certain kinds of breaking changes in additions, it's significantly better for people to be able to upgrade, not only because the opt in nature of things, but also just like Rust is still going to be Rust, even if there are some tweaks out, it works. And some changes like the core idea of Rust will be the same. So let's talk a little bit about what I mean by breaking changes in an addition. So I think one of the best examples of a breaking change was the async keyword. So Rust has, you know, as I said, two additions right now, 2018 and 2018. And in Rust 2015, code is, you know, async is not a keyword, but in 2018 it is. And so what that means is, if you look at this code that I have here on the left, we have a function named async that just takes an integer and returns it. It doesn't do anything fancy. But we call it passing into five and use underscore s as the name since we never use the variable to get rid of that kind of warning. So if I run this code on Rust 2018, as you can see, this is the playpen interface on play.rustlang.org. You can choose this little drop down with the three dots and then pick which addition you're in. So if you choose Rust 2015, this code will compile and it runs, doesn't do anything because we just, you know, pass an integer around. So there's no output. But if we change that to addition 2018, we will get an error. And this will say, expected identifier found keyword async. So we're allowed to name a function async in Rust 2015 because it's not a keyword, but we're not allowed to name it in async in Rust 2018 because it is a keyword. So this is an example of, you know, if we purely made this change in the language, code that existed and ran just fine before would end up breaking. So this is like a breaking change. But because you can choose whether or not to upgrade, it's like not a breaking change. And so this kind of like duality, it was a very controversial around coming up with the plan of additions. And it was also one of the big challenges of communicating this to users, like technically it's breaking, but it's also not breaking is very interesting and kind of unusual. Is my mic still working? All right, cool. Dropped out there for a second. So the way that you opt into this change, if you're not on the playpen, because most serious Rust programs are not running in the playpen, that would be ridiculous, is in the cargo.toml. So you get to choose an addition key by putting 2018 in there. And if this does not exist at all, then it defaults to 2015. So all of the code that was generated before we had this idea of additions, it is able to, you know, stay on the sort of the default 2015 edition. But if you opt in, then you're able to do this. And cargo new will start generating, you know, 2018. So I just typed cargo new to generate this, and it defaults me to the latest. And so that way, you know, we're able to like new projects start in the latest edition, but older projects stay on the addition they were created with until their creators explicitly opt in. So that's kind of like the way that this happens in most real projects. And one thing that's really important, though, about additions is that additions can interoperate just fine. So let's say that I had packaged up my useless async function into a crate, and I wanted to use it from some code that was in Rust 2018. Well, one of the features that was added in Rust 2018 was the ability to use a raw keyword. So I showed you the error message in the 2018 code before. Right below the error is a little help message that says, hey, you can escape keywords to use them as identifiers. And so here with this r pound sign, both at the call site and at the actual declaration site, you're able to still define and call a function named async, even though it's a keyword. So this would matter if you could imagine that the async function lived in a 2015 crate, then I would still be able to call it from a 2018 crate. And, you know, vice versa, if there was some other way of doing it. So this is one example of the ways that code can interoperate. But just in general, like kind of the idea is that you don't have to be worried about your dependencies at all. Other code is allowed to be in any addition, and they'll compile into your project just fine. And there's no like worrying about this kind of interoperability compatibility, other than if, you know, some keywords are named a certain way, and then you have to know the escape mechanism. But what this means is we don't have the situation whereby when a new addition comes out, everyone is forced to upgrade all at once, because that doesn't happen. It takes a long time. And, you know, there's always some people that are going to sort of prefer older things, and we don't want to like bifurcate the ecosystem. And so this way, these versions can live in total harmony, and your dependencies can upgrade at their leisure, and you can, you know, upgrade as fast or as slow as you'd like, and you're not locked out of the rest of us world. So that's a really like helpful way to make sure that all this operates smoothly. And so specifically, I'd mentioned before, part of the way that this works is that additions are not allowed to change everything. So these are the rules that were set out in the original RFC, and they're not complete. So this is not necessarily like a full list of everything that can and can't change. But I wanted to like point out some specifics. So an example of a thing that can change, as I've already showed you, is new keywords. So we're allowed to define new keywords and new additions. And, you know, that's totally fine. It's like I said, they interrupt across the boundary, no problems. The second thing that additions are allowed to change is allowed to repurpose existing syntax. And I say repurpose because like, you can remove existing syntax, it's like how it gets repurposed. But like, it generally shouldn't only remove, it should like replace with something that does something slightly different. So an example of this is, if you have a usage of a trait, in this case, I'm just calling it trait. But, you know, if you're using this as a trait object, you would just use the name of the trait originally. So you'd have like box trait or arc trait, something like that. And so what we did in the 2018 edition was we sort of deprecated that usage of just trait on its own. And we introduced dine trait. Unfortunately, my slides kind of put this on the two lines, normally it would be just one line. But like, this helped you know that hey, this is a trait object because we're doing dynamic dispatch. And so we kind of like replace that existing syntax for doing a thing with a new syntax instead. And so you're able to, you know, use this new syntax, and it's like more clear to people that dynamic dispatch is what's happening. So we're allowed to kind of like, change some existing stuff and add some new things and like tweak things. Another example of something that changed in the 2018 edition was the module system, which is a pretty big change. I'll talk about all the changes we made a little bit later. But there's also some things that we can't do. Earlier I mentioned that we couldn't make really big sweeping changes. But like there's actually slightly more specific things. Some of them are based on practical limitations, and some of them are based on decisions that we've made. So for example, the coherence rules can't change across editions. If you're not familiar, a coherence rule says like if a type implements a trait, is it allowed to implement that trait or not? Like do you get a compiler error when you try to compile a trait implementation for a type? So, you know, a common example of this rule being broken is that if I had say, a type that's defined in the standard library like string, and I have a type that's defined in a third party package is not mine, say maybe like serde, I can't define serde serialize for a string because it's not my trait, it's not my type. So that doesn't work. If I had made my own string type, then I'd be allowed to implement serde's trait for it. And if I implemented my own trait, I'd be allowed to implement it on the standard library string. But I have to own either one of the traits or the types. And the rules are a little more complicated than that. But like that's the gist of it. That's the biggest thing. So that's not allowed to change. We couldn't say relax them in one addition, but not in the other. And that's because cloh coherence rules are kind of global. And those rules happen across different crates. So if we had different rules for different parts of your program, that would be extremely hard to implement, very confusing, and possibly just unsound, like, it's not kind of a thing that you're able to do for all of those sort of reasons. So, coherence rules have to act globally. And so therefore they kind of have to stay the same in every addition no matter what. So that's a trick. Secondly, another thing that people sort of don't always appreciate is that we can't make breaking changes to the standard library. And intuitively, you're like, wait, if I can change crates, standard libraries just create, like why not? Well, I mean, it is just create, but it's also kind of not just create. You get one copy of the standard library for your whole program. And so if you had a dependency that used Rust 2018, and then you use Rust 2015, say, then you would need both copies. So it doesn't like really work that way exactly. So we're able to sort of deprecate things, but we're not able to remove them. And there's some talk of maybe having some sort of visibility situation where like, they exist, but there's some visibility rules where this is like only allowed to be seen in 2018, or 2015. Those are proposals and they're not like real yet. So, you know, this is like kind of half a true technical limitation and half a sort of social limitation. Somebody asked a question on Twitch. How does a deprecated feature move from deprecated to like removed? And can that be done between the two versions? So one interesting thing about this is that some of this stuff is kind of up in the air policy wise ish. Basically, like things cannot actually error on the same edition. So like usually the way you think about it is something that comes a warning in the old edition, and then an error in the new edition. And the original RFC talks a little bit about code that's being free on the first edition should compile. Maybe you'll have new warnings, but it won't break on the second edition. But like if there's warnings in your first edition code, maybe the second edition would break. I'm going to talk a little bit more about this at the end, because the exact policy is like a thing that we're talking about. So yeah, the rules are slightly up in the air, but originally that's what the intention was, was that like, you introduce warnings in the first edition, you remove them in the second edition. There's some questions about whether or not that's like too fast, or maybe we should like require a whole edition to go by. Like we require language features to wait for a whole release in nightly before we're able to stabilize them, for example, there's kind of a mandatory minimum waiting period. So maybe there would be a good mandatory waiting period for deprecations. But yeah, so I hope that answers enough of your question. Hey, Jared. But I'll talk about a little more. Okay, so why do we have these restrictions, like on some level, like I talked a little bit about some of them with like there's one crate everywhere. But let's get into some details. And I think this matters because this also really helps you understand like why certain things are allowed and why certain things aren't allowed. And it's also just kind of fun to talk about the compiler and how it works. So this next section is going to be about additions, I swear, but it's also kind of how the compiler works because I think that's interesting and kind of matters. So Rust is currently sort of kind of there's an asterisk here, I'm going to get to it later, what's called a multi pass compiler. And so this is like a classic architecture for compilers. If you take a compiler class in your university, this is all the teach you compilers work. A lot of compilers in the world are implemented this way. Basically what happens is there are this concept of passes. So you can you take in a source code, and then you spit out something. A lot of older compilers are called one pass compilers because they directly turn the code into the actual like binary code. So if you think about like used to have to be a lot of older languages required you to define a variable at the start of functions, for example, that was because they had one pass compilers. And so they needed to omit the stack space for those variables. Okay, it seems to be back cool. I don't know why that's happening. It's probably something on my end. But anyway, so yeah, so older compilers are one pass. That's also why a lot of them were super fast, because they didn't do a lot of this stuff. But over time, you know, we needed things to be more complicated. And so then people develop multi pass compilers where you would do multiple steps. So you'd iterate over the source code in multiple ways. And that's how it's produced. So in the Rust compiler, it's like multi pass architecture is traditionally existed. And is similar to many other compilers, basically of input being source code. And it kind of goes through each of these steps in turn. So the first one takes the source code, and it creates an AST out of it, which is abstract syntax tree. And then it takes that AST, and it produces here, which is high level IR. And it takes the high level or IR, and it produces mirror, which is the mid level IR. And it takes the mid level IR, and it produces MLVM IR, and then LVM takes that and produces the final binary. So there's a bunch of these steps. And within these steps, there's kind of smaller steps. And all this sort of like happens, we're going to talk about this in a little more detail. So compilers traditionally are kind of produced in this three different phases. That's why you have these passes, you do the full pass and the full pass and the full pass, all three steps. First one is like a lexical or syntactic analysis. So is your code well formed? This is like grammar rules. So, you know, does the sentence I'm saying follow proper grammar or not? Does your program follow the language as grammar or not? Secondly, is semantic analysis, which does this code make sense? So for example, you know, I could, I could say like, you know, this sentence is false. And that sentence is grammatically correct. So it passes lexical or syntactic analysis. But semantically, it's very unclear what it means. Because if it's true, then it's saying it's false, which means it's false, which means it's not true. So some reflexivity there. It's just the first example I could come up with. But like, you know, you can imagine gibberish, for example, that uses all real words, maybe it's structurally correct, but it doesn't actually make any sense. So semantic analysis makes sure that the thing that you've said is sensible. And then finally, code generation, this does not really have an analog in existing languages. I guess this is the vocal chords turning it into sound. Maybe it would be the analogy, stretching this a little too far. But once we verify that everything works and makes sense, we actually produce the binary, finally out of it. This step in itself has a bunch of different passes. For example, we talk about optimization passes, and sort of run and generate code, you know, faster. So that all happens in this kind of stage. But you know, these are kind of the three big giant steps. If you've ever wondered how Cargo check works, for example, cargo check will run the lexical and syntactic analysis and the semantic analysis, but won't generate any code. So this is an example of how understanding this can help you practically as a rest developer, use cargo check to check your code makes sense. But you don't actually want to run it. You can save yourself a lot of time by not making the compiler do code generation. So this is like one example of how this architecture lets you do less sometimes. So it's kind of like two sorts of these steps between these situations. And this is kind of some compiler jargon that you may be interested in. So one of them is called lowering. And so that's the word that you use when you talk about going from one form to the other. So for example, mere is lowered into L of the MIR, or the AST is lowered into here. And the reason it's called lowering is that at every step along the way, things get simpler. And we throw away things that we've already validated, which makes future steps easier. So for example, MIR does not have the concept of complicated fancy loops. So like for loops, for example, don't exist in MIR. What happens is the previous steps in the compiler take your for loop and they turn it into a while loop with a break in it. And so MIR is able to understand a while loop with a break. So we've sort of removed a construct from the language when we've gotten to the lower step. And that is why the rest of step is simpler. And this definitely really matters. And that's why it's called lowering is because you're kind of breaking down what is happening into simpler and simpler things. And then finally is a step called a pass, which basically means a sort of check that validates that your program is well formed. It does not necessarily do a transformation, although technically it can. So for example, type checking is a pass on your code. So it runs over your code and it makes sure everything makes sense. A lot of things are kind of passes. And sometimes they will do transformations. This is like whenever basically like, okay, you know, I'm going to take your for loop and I'm going to rewrite it as a while loop. That happens first as a pass, because inside of here, I believe. And then the lowering step is what turns that simpler form of here into MIR. So they kind of like work together. Okay, so this is some example of actual code going through these steps. And I did this about a year ago. So the samples are a little dated because of the fact that the compiler output changes all the time. But conceptually, it's the same. So I figured it being outdated actually a little better because you shouldn't get hung up on the specifics. So, for example, let's talk about taking code and producing an AST. If we have this function called plus one takes 932 adds one to it returns it. We can actually ask the compiler to print out the JSON version of the AST. Because again, these are all data structures inside the compiler. So they don't really have a text representation, but you can like print them out and things like JSON. So for example, plus one, a little bit of it looks like this. So there's a statements, and that's an array of nodes. And inside of there, each node has a variance. So this is like an expression. And then, you know, it's like a binary expression that's add, you can kind of see how these little bits all fit together. And then, you know, we're adding X, and it keeps going on to talk about adding one and stuff. So you kind of get this data structure view of your code. And that's what Rust AST looks like. So here, you know, we take our statements and the statements refers to an expression. Expression refers to a binary expression. The binary expression says, hey, we have an add expression that adds X and one together. So this is kind of like why it's called a tree is because if you see there's like this root, which is the statements and then there's the branches and leaves that happen to build a tree. So this is like what an AST kind of looks like visually. And so, yeah, fundamentally, the AST is a data structure. And it's the way that our code looks written in words, but is a data structure. This means it's easier to manipulate. Like, you know, if you just have a data structure, you can just manipulate it like that's what they're there for. But if you had to do it on the like textual representation of your code, it would be much harder. So the idea is that we break the text down into a data structure and then we do all our operations on those data structures. So from the AST, we move on to the here. And so here is short for a high level intermediate representation. And this basically is like doing form this sort of checks. What I mean by form this is like, you know, have you imported all the stuff that you've used things like that. And some things are simplified. So for example, in my understanding here does not have, you know, like use statements, they get turned into the elaborated like full versions of all the types. So an example of what, you know, kind of like the sort of transformations that happens here. This is a very simple for loop. There's a reason I reference for loop several times earlier today, where we take a vector of five integers and we loop over it, printing them all out. So the AST would take that literal code is written and represent it that way. But when it gets lowered into here, it ends up being something more like this. So this is like still rust code that you could write in theory. But you'll notice the for loop is totally gone. And we now have a loop with a match statement inside. And when we turn the thing that we're iterating over into an iterator, and we, you know, call next on it repeatedly, until the body of the loop happens and all these things. So you can see how it's kind of like simpler in the sense that there are less language constructs. It's more complicated in the sense that there's more code. Because like that's the reason we write in the higher level stuff in the first place is because it's easier to understand for humans. But the computer, you know, having less things makes the analysis much simpler. So we do that kind of stuff. Most checks in the compiler today are done on here, at least in my understanding. So here was the original Rust IR that existed. So the first version of the compiler, or maybe first is a little strong, but like for a very long time, the compiler turned everything into here. And then it went to LVM IR from there. So, you know, it's kind of like the og thing. So a lot of things are written in terms of here. So two things that are still written in type check, or in here are type check, which is like, do all the types make sense and have you not made any type errors. And then finally method lookup. So that's done at compile time instead of in some dynamic languages method lookup is like a dynamic process. But basically, you know, kind of look at like, you know, what, what trade are you actually calling when you call a method or is there a trade is an inherent method, those kind of things. These are all done on here. Then we move from here to mirror, and mirror became the subject of a lot of discussion in the Rust world. So you may have heard about it over the last couple years. Mir is ultimately about control flow. So here is kind of represented our code in the way that we wrote it. But mirror totally rewrites it to be in a simpler form, but also one that's based on a control flow graph is the term, rather than an AST, which is the tree. So going from a tree to a graph is, you know, helpful for certain kinds of analyses, specifically like the graph represents the way that the control goes through your programs like which statement executes in which order. And that matters because, for example, non lexical lifetimes, it needs to know how the execution flows within your program to work. And so it was very difficult to write that pass on here. So like this is a practical example of why this stuff matters is that we had to invent mirror to make non lexical lifetimes feasible, because we needed to be able to encode that flow control to be able to make it actually happen. And I say we, because I'm on the team, but like I did none of this work to be absolutely clear about it. A lot of other really great people made it happen. I don't know what's up with my audio dropping. Anyway, so another interesting thing about mirror beyond the control flow move is it's kind of the core of rust. So it's kind of like everything that's rusty about rust without any superfluous extra concepts. So like I said earlier, fancy loops are gone. Everything is purely loops and breaks. I think I might even have go tos correctly. But Baro checking is done here because, like I said, non lexical lifetimes, kind of mirror is kind of like the core way that, you know, what makes rust rust. And it's kind of like a representation of the computer of what rust is like. And as example of what mirror looks like, if you dump out an example, again, this is a little old, and this like pseudo rust is not actually rust code. But it kind of looks like it again, we're printing a data structure that doesn't have a real text representation. So here you can see our add one function, it declares two variables zero and two, or one is the first parameter. And in a BB zero stands for basic block. So the pay attention to control flow, we have this idea blocks. And so it'll say, hey, storage live means that the second variable is live in this area, which is an analysis happens about control flow. It's too complicated for me to get into and I'm too far in the weeds already here. You can read the docs in the compiler if you want to see all what's happening. You can see our call to add, you know, adds a constant one and our number two, and then declares the storage is dead and then returns. This kind of what mirror looks like again, not anything you ever have to worry about as a rest programmer but if you want to see all the compiler sees your code, looking at mirror can be really useful. And then finally, miraget's lowered LLVM IR LLVM is a compiler toolkit that you can use to kind of like build stuff. It's a VM and like the technical sense of VM but not on the way that everyone uses the word VM so you stand for low level virtual machine but the LLVM project changed its name so that it no longer me references virtual machines because that got too confusing to many people. So basically, what we do is optimizations and code generation are done by LLVM for the most part. There are a couple optimizations that happen in mirror, and we hope to do more of them in the future, but Russ would not be anywhere where it is today without LLVM so it's very important to us. And it kind of like is the lowest level of the compiler sort of operates, you know, LLVM takes the compiler's output and produces the binary so we kind of like handed off to that library is the last couple steps. Andrew Livret, sorry if I mispronounced your name, is asking what is the timeline if there's one to get SIMD support unstable. So SIMD is actually already unstable for Rust, but only the X86 versions so it's also the low level unsafe primitives. So I think maybe you either one don't know that's true which is totally fine but that does exist today, or two you're talking about higher level SIMD which is like what you would want to write as a regular programmer instead of the intrinsics. I don't actually know that there's a group working on the higher level stuff right now. The LLVM stuff does work though on X86 at least, and given arms recent interest in Rust, I'm assuming that arm assembly stuff will be soon to follow. I think maybe some of it already works, but I'm not actually 100% sure. So yeah, still more work to do there. Don't know the exact timeline yet. Question by jam one Garner. What would go to be used for in mere just more complicated breaks. Basically like structured programming is useful as the programmer like we write loops because we don't want to have to think it go tos, but go tos are conceptually simpler because they are allowed to do whatever. And so it's actually easier for the compiler to understand than the higher level constructs. So I actually like I want to emphasize like I don't work on the compiler myself so I believe that go tos exist but I don't actually 100% remember. So I might be a little wrong there. So you should you know if you care about this topic should look into details a little more, but I believe that that's the case. But I'm not 100% sure. Finally, there's a question about working with Rust and fuchsia I will talk about that towards the end because it's not relevant to this part of the conversation so I'll get back to you SpaceX Jedi don't worry about it. Thank you for the question. Okay, if you're curious what what LVM IR looks like. This is an example of the text version of LVM IR so you can see that the functions name is mangled so it's add one but with a bunch of other shenanigans on top of it. And, you know, we add a number to that and return it very straightforward. There's a whole bunch of attributes and other stuff. So this is kind of like what we hand off to LVM. It does optimization passes there shouldn't be a lot of optimizing to do in this code other than maybe inlining it into other code we've written somewhere else. So, you know, all that kind of thing. Okay, the last thing I need to mention on the compiler architecture before we go back to how this manage it how this works with additions I hope you'll forgive my little compiler tutorial here is that I said before we were a multi pass compiler and that's true but we're also like working on making Rust query based so a lot of the compiler is already query based. And what that means is instead of these kind of passes where you take the whole source code and you turn it into one AST, you take the whole AST turn it into here, vice versa, like you're continuing, you know, down that strategy. Rust instead uses this concept called a query to create an executable. So what happens instead is the rest compiler will say something like hey what type is this function. What's the body of this function. And then the compiler will operate in that fashion instead so instead of it being like here's the source code of your program and turn it all into one way. The compiler will say like give me the you know what where's this function and then the internals the compiler will say oh, we don't have this function yet, but you know, let's load up the source code of what where we you know think it is, and then we'll look at the body and do all that work, and then sort of figure out that way. And so it'll sort of do all the steps, but in smaller chunks instead. And the reason this is useful is first of all memoization. So you're able to, you know, reuse results of these queries across different invocations of things. And so that's helpful for compiler speed, but also more importantly it fits increment incremental, incremental compilation can say that incremental compilation it fits it much better. And so, you know, for able to just say like, Oh, the body of this one function changed that would map directly to one compiler query of saying get me the body of this function. And so then you would only do that part of the work, instead of saying like okay, you change the body of this function now we have to redo the whole AST and the whole higher level I R and the whole middle level I R. And so this is kind of the way that sort of production grade compilers are written today, rather than the way that they're taught in the middle. This was started by C sharp with their Roslin compiler so if you're more interested in kind of how this works should look into Roslin or rusty as we continue to make it happen this way. All the mere stuff is written like this in my understanding, some of the older code is not yet converted but this would kind of be how the stuff sort of works. Also if you've been following rust analyzer lately. So this is kind of the way that it has this sort of model of like highly incremental and like not traditional architecture that compilers have so that's all how that goes. Okay, so additions aren't allowed to break everything but like how does that mean, like what's that mean. So for compilers, basically like additions aren't allowed to differ by the time you get to mirror. So, you know what that means is a little fuzzy from the outside, basically what it means is the core of rust mere stays the same no matter what. And that really matters for a number of different reasons. The first thing is that like, because it becomes a common language for all the additions. It's much easier for the compiler team to sort of manage changes that are brought on by additions. So all of the stuff that happens differences and additions happen earlier stages than mere. So what that means is we can assume no matter what going forward that mere is like relatively stable obviously the changing the interface but I mean like, we don't have to switch on things by the time you get to that step and so everything is sorted out earlier. And this happens to make interoperating between additions easier because you know your 2015 code and my 2018 code will both compile into the same mirror at the end so that's how we guarantee interoperability because they're both speaking the same language at the, at the, you know, bottom of it. Because this is the primary mechanism by which things become interoperable. And it's also the way in which we can like control the amount of breaking changes because if you need something that would change things like very fundamentally, then we can't do it because we need to have this sort of interoperability layer. On a human side, not being able to break things in mere means that things can change per addition but not that much because like the core understanding of rust and what it is is going to be the same no matter what the sort of like high level details are. And so that's really important. It also means because we are compiling down at the same thing we have this interoperability when else but the ecosystem and that really matters. Hey Jared has another question. Would adding more query based compiler features to rust see make rust analyzer and other sort of analyses tools more robust. Yeah, basically that's exactly like the reason that C sharp underwent the Roslin project is IDEs have very different needs for languages than the traditional compilers do. And so they kind of like reoriented around what happens in an IDE. That's exactly why I phrased it is kind of like, oh I changed the body this function let's not recompile the entire world, because that's what happens when you're actually in your editor programming as you change little bits. Most of the programs program stays the same. So we kind of want to reuse that work, rather than changing, you know, throwing it all away every single time. And so yeah, it's definitely one of the reasons why those tools are better is because they want this kind of architecture. So yeah. Okay. And then another thing about like what is additions towards the end, you kind of think of additions as sort of like a bigger release cycle. So rest already has three different release cycles are stable beta and nightly, and there's different cadences to those releases so nightly is every night stable and beta happen every six. Okay, so, you know, additions kind of like our like a bigger release cycle that happens, you know, broader than versions. But we don't have a cadence for additions yet. This is kind of why this talk exists. And we're working on our FC that I'll get to here at the end, but basically like, we didn't actually decide whether or not this would happen on a schedule or not when we decided to do it in 2018. So there's no policy in the initial RFC about when additions should be used, as I sort of just mentioned. It didn't talk about when it just mostly was talking about how. And that way we could focus on shipping rest 2018 and not worry about it until later because, you know, there's a lot of stuff going on. And we want to set that policy immediately we wanted some experience with additions, we wanted to get it 2018 going and we don't want to think about it basically. So that's been a couple years time to start thinking about it. So 2018 was sort of the first edition but we kind of retconned it to be the second one so that's 1.0 and that's 2015 where the very first edition sort of speaking. 2018 was the first one that kind of like changed things. And so what I want to talk about next is like a little look back about how that happened because I think that really informs what we should do in the future. And this is also again kind of like why we didn't pick a policy back then is we wanted to be able to see how it went and then think about the problem later, rather than trying to invent it beforehand. So let's talk a little bit about rest 2018 and kind of how it went. So I think overall rest 2018 was a success. We achieved our goals, even though it was a ton of work, but we did ship the addition, it did happen. We managed to understand this was different than rest 2.0 and they didn't like run away thinking that we had totally destroyed our stability guarantees. Obviously, there were some people that were kind of not happy that we did any sort of changes but you can't please everyone all the time. But the fact that it was a different kind of mechanism helped people understand what we were trying to accomplish. And I would say that there are not any real major issues with the addition system itself. At this point, there's some tweaks and things, but like, you know, the actual rollout of the implementation went smoothly for the most part. It was a lot of work. It was a really big project for all the teams. We never really had undertaken such a big project before other than maybe rest 1.0, which is again sort of kind of like an addition. And so we managed to do it and that's positive and that I think is worth like celebrating. However, rest 2018 was also not a complete success in my opinion. So there's kind of two different ways that I think that really struggled. The first one was the schedule and the second one was the team. So we didn't ship everything that we wanted to ship in the 2018 edition. Some things didn't actually get finished. Some things changed significantly and scope had to be cut drastically in order to make it under the release line. And so while we did ship the mechanism and it was successful, it just barely happened. The release, as I'm going to talk about schedules in a second, happened in December of 2018. We actually did not have another Rust release. It happened literally at the last moment. And so that also is, you know, a sign that things weren't necessarily as ideal as they could have been. Secondly, it was the human cost of the addition, the team. Tons of people put in tons of work for a really long time to make this happen. And it was extremely high stakes because this was a really big thing and it was the first time we'd ever done it. So that contributed to a lot of burnout amongst contributors, I believe. I can only truly speak for myself. I was a total freaking mess by the time the 2018 edition actually happened. And I wasn't even the one implementing a lot of this stuff. I was just trying to like keep the book going and do some other work. So other people worked a lot longer and harder than I did. And I felt terrible, honestly. So I can only imagine with other people, you know, how they felt about the schedule. So we did it, but like at what cost. And so, yeah, the 2018 edition shipped on December 6th, 2018 with Rust 1.31. And what's kind of funny about the half shipping thing too is like some actual changes didn't ship until 1.32, but the addition self-shipped in 1.31. So, yeah, we shipped a bunch of different things. This is a screenshot from the blog post. So non-lexical lifetimes happened in 2018. Module system changes got simpler in 2018. We did some more elision stuff. Constant functions became a thing. Things like Rust fix got added, a whole bunch of lints like Clippy was able to do its job on stable. And that was a big deal. Documentation got updated. We had the new domain working groups and new website. Tons of things happened in the standard library. Lots of new cargo features. There was just like all sorts of stuff. Like 2018 was huge. It's a really big deal. We shipped a lot of it and that's deserved celebrating. But as I said, it was behind schedule. So the initial RFC had sort of this schedule. There's this idea of a preview period, which is kind of like you can think about the addition being unstable. So the idea was that like, okay, Rust 123 is going to start shipping a preview of the addition. And then in 127, we're going to like nail everything down and actually ship it. And that'll be when it comes out. So to put some dates on that, 123 was January 4th in 2018. And the final 127 release was going to be June 21st, 2018. So halfway through the year. And if you're paying attention to a moment earlier, that was very different than what actually happened. So what actually happened was the changes landed in the nightly compiler on the 6th of February. So that was almost one month later than the initial release was planned. And then finally, the actual release was in December, which is like six months, June to December, something like that. A long time later. And we kept thinking it was going to be in like October and then that slipped and then November and then slipped and then December. We finally got it out the door. So we almost missed the date itself, which is intense. I think that this happened because we tried to do too much. Partially that was because there was a lot of work to do like, Rust 1.0 was a really small release. And there was a lot of things that really needed to be tweaked. We had this opportunity to do it. So we committed to it and we made it happen. I think another part of sort of some of the problems was some of these ideas, we tried to move too far in front of the community. So like some of the things around, for example, the anonymous lifetime were added. And I'm not even sure that people like know about the anonymous lifetime or use it exactly because it kind of got lost in the shuffle a little bit. But we had some ideas about some patterns and they got scaled back and then some things got sort of like cut or barely shipped. And we tried to like move too far ahead and think about like what things should happen rather than taking what happened and like getting the good parts of it. There's always a balance to be had there. I think that added some stress. The module system was another example of this where we like kind of invented what we wanted and then there's a lot of changes, a lot of feedback. And it was really, really difficult to get that through. Finally, the other reason why I think we bit off a little more than we can chew. So we have, we're really, really great that we have so many contributors to Rust and we did at that time. But also contributors are not employees. And it's much harder to plan a big initiative that spans a whole year when you can't be guaranteed that there's like these people that have full time amounts of work to work on it. Like just from a project management perspective, you know, people are free to come and go as they please on the Rust project. But that also means that when you're trying to like get a huge thing shipped on a tight deadline, it's difficult to be able to rely on people having the ability to do stuff. And you know, even if you are an employee, like I said, I got burned out. I didn't want to do this anymore to some degree. And so, you know, it can just be really difficult with these kind of big initiatives in an open source world. I don't think that anyone has figured out how to really accomplish this yet. Another positive thing was we proved that the mechanism actually worked. So 2015 and 2018 interoperate just fine. The plan was good. It happened. You know, you don't have to worry about this thing. We can have our cake and eat it too, which is the thing we always try to do in the Rust world. We didn't split the ecosystem. There's not a holdout of people that use 2015 that like are sequestered from the rest of the community. And so that's like really important. There are still people that program the 2015 edition today and they can do everything they need to do and it works just fine. So that's I think a really important thing. We've kept some coherence. And I think that like it works so well because it's pretty much silent. Like I don't think most users think about it. It is just a whole ton, which is part of why I wanted to start this talk by putting out all the details because like it just kind of works. You normally think about it, I think for most people and that's a testament to how good the thing that we shipped was. But as a downside, we underestimated the cost of the addition to both the human element, but also to like our users who needed to make these changes happen. So even though we put a lot of time and effort into making upgrading easy or simple, it wasn't actually so in the end. And that's just because there's a lot of moving pieces. So we had Rust fix, which was able to automatically upgrade your code, but like it wasn't perfect. And there were some things that couldn't necessarily update some of the fancier features and you know, people still have to like validate and test and do these kind of things. And so it just takes a lot of time. The compiler did not shift to REST 2018 for a little while. You did other big projects. And I think that's also okay, like expecting everyone to upgrade immediately is part of like an unrealistic expectation. And I don't think we totally had that, but there's definitely some people that thought that should happen overall, like in the community or on the teams, because you know, they worked on smaller projects. But you know, some production users reported that it took them a while to upgrade to 2018 and it was a significant costly kind of upgrade. You know, even if it's easy to do, it still takes time and time is money to companies and companies are the ones that have the biggest Rust projects because they're paying people to work on things full time. And you know, we sort of put a big burden on a lot of our biggest users and that's tough. So I think that's a challenge. I think another thing that happened with the 2018 edition is it became feature driven instead of time boxed. So, you know, normal Rust releases or time box, that is there's a schedule and the release happens, train leaves the station, regardless of whether you make it or not. And so that's kind of what happened. And REST 2018 sort of became designed around features. We sort of said like, hey, what features do we want to happen? And then we figured out how to make them happen on the schedule. But then when they took longer to implement, then they took longer to implement them. Maybe we thought, you know, that became kind of an issue. And so that was I think a lot of the struggle was like, we need to get these features out and there's this time deadline and we have to have it happen for the time. That doesn't happen with normal Rust releases because there's always a new train coming in six weeks. Like part of the reason why we picked the train model in the first place is because we knew that having a yearly or longer release schedule was a problem. So then we decided with the addition system that we were going to do that. So I think that was like a big issue. Kind of felt like lead up to Rust 1.0 where there was this big giant release that happened and everybody worked super hard. You know, this was a huge amount of hard work and herculean efforts by folks and therefore some burnout happened. And so I think that that was a big problem with 2018 was getting too caught up in like, it means this set of features and we're going to ship them on this day. And so a great example of how this did not happen and was very successful is async await. So, you know, we realized that async await was not going to make it in 2018. And so we said, hey, we're going to reserve the keyword so that we have it in the addition, but we're not actually going to release the feature. And so what that meant was that, you know, so 2018 December was when the addition shipped, but we actually shipped the async await in 2019 instead, almost a year later. And I think that worked out really well. And it's a great model for how this should sort of work in the future is that we don't necessarily like, you know, do we don't force everything to happen, and we don't force the schedule of the addition to happen on a feature basis. We kind of say, hey, the future is going to be on this cadence. And, you know, we're going to ship the feature when it happens. So that's important. This is kind of blending into the last part of my talk here, what should we be doing. So this is kind of like my opinion on where we should go from here. Basically, we should have a rest 2021 edition. I know that every talk with a title in it supposed to be no, but the answer is yes. Gotcha. Betterages law of headlines. But I think that we should have a 2021 edition, and we should commit to a train model for additions and we should have one every three years, no matter what. I think that this should be smaller than Russ 2018 was, for a number of reasons. First of all, I don't think we have as much need as we did in 2018. But secondly, like, you know, I think that it will just go smoother if we don't do as much. And I also think that a lot of people are sort of craving stability in the rest world. And so I think that that's like a very positive thing. So a smaller edition would be much smaller than 2018, but I still think we should do it anyway. There's a question from Emmanuel Lima in the chat. Does Missila hire engineers to work on Russi and that should help to manage burnout. No, Missila does pay some people, but it's a very small amount of the overall team. And there's no indication that Missila is like going to hire 10 more people, which is like what we would need. So yes, while they could in theory do that, I don't think the Missila is going to. And I don't always think that just hiring people is always the right solution either, because, you know, it depends. Like we could hire the community and that'd be great because they already know what's going on. But that doesn't necessarily mean that's the right call because like not everybody wants to do Russ's their job and like it's complicated basically. But it's true that work helps diminish burnout, but on some level work can also force you into burnout. Because when it's your job, you have to do it even if you don't want to. So like deadlines are somehow weirdly more stressful with jobs than they are with open source projects, I think. So, you know, like I said, I was a Missila employee at the time of the 2018 edition and I got burned out anyway. So I don't think it's a pure solution. I do think that can help in some cases. Yeah. Okay, so release trains like the core of my argument with the 2018 2020 on edition release trains are good and additions are kind of release. So we should have a train and that should just be the end of it. Like we should no longer pick date based releases. We should just always do trains because they're just far better way to ship software. If six weeks go by without a new release and a new feature in the regular code base, we still put out a new Russ see anyway. Some additional some releases are small, some additions are big. You know, that's just the way that it goes. And so I think that if there's three years go by and we don't need any big breaking changes, it's totally fine. We should still release a new edition. Sprutellel asked a question in the chat that I'm going to be getting to very shortly. So stay tuned. Yeah, like basically I think the train model has been wonderful. And I think that we should do it with additions too. There's a number of reasons I'm not going to get into all of them. But basically, like the shortest version is it's a model that works and as a model that we've demonstrated is feasible. So I think we should just do the same thing, but on a longer schedule. Some people argue that the social part of addition shouldn't matter and that we should only make additions happen when we have the feature need. But I think that that's wrong. Some of it is just the classic arguments back and forth that happened the first time the addition happens, like looking over the past three years matters, getting people outside of rust pay attention stuff matters. And all that stuff still happens. I think the smaller additions are actually a nicer marketing message. So shifting them to somehow more important in some ways than a big breaking change release, because it's like, hey, it's been three years with rust and we don't feel the need that there's any big breaking changes because we think the language is good enough. That is a very strong and powerful marketing. Message to people to be able to want to check things out. People are still like leaving comments on the internet all the time about like, I don't know that rust is actually stable because of the six week cadence like people don't necessarily know how much time and effort we put into making sure those things are stable. And so, you know, every six weeks seems fast. So people get on the idea of like, oh, I only deal with rust every three years feels better to a large number of people. So I think that really matters. So, yeah, there's another question in twitch, I will get to in one second. So, okay, Spoodle here is your question on a slide. So what features should be in rust 2021. I actually don't care personally. There are some features I want, obviously, but I think that we should do it regardless. And I don't think that we need to have a specific feature to justify doing an addition. In fact, I kind of think the argument is stronger purely on the like release engineering and marketing angles and not on the feature based things. Part of this is also because like consistency and scheduling overall is key. If we miss something that misses a train, it can get on the next train and that's fine. But like, if we release additions based on features, and every time we have a new set of features, we have to re litigate this entire conversation. And we already did it first with 2018 edition and we're doing it now to set up this policy. And I would like to not sort of like have the rust team be arguing every three years whether or not we should be releasing an addition or not, but we're arguing like even more often than that. Like, you know, if we do it on a feature basis, then it happens at random kind of times. And we just say like, hey, this is the mechanism that happens on this schedule. Period. Then we can free our time actually working on making rust a better language rather than worrying about this policy. And so I think that that's actually the sort of most important kind of thing. I will answer that question, Fred go afterwards. Why three year cadence. It's just like a nice length of time. C++ has a three year cadence as of late and yearly is too often because like there's not enough stuff to sort of accumulate to make it a big enough deal every year. Five years would be far too long in my mind. So I think three is kind of a nice compromise and it fits similar to C++. And so I think that that happens. Specifically, I bring C++ up because C++ OX I think is a cautionary tale that we didn't really learn enough for for the 2018 edition and it feels very similar to the 2018 edition for me. So the first draft of the standard of C++ was in 2008. C++ O3 was the previous year of the standard. And so Bjarn and some other people were hoping that this would be C++ 08 or 09. So they named it C++ OX. The problem was that they made it on a feature basis and it took them so many years to get through all the details and ended up shipping in 2011. And so people used to joke that it was becoming C++ OA because like they had missed like with 08 or 09 scheme it slipped to 10. So it should be C++ 10, but they had already said OX. So like, you know, this demonstrates some of this kind of like conflict here. And so that's when they decided to move to the train model for the C++ releases was like we're releasing every three years because like this was just not great. And so I think we had a similar kind of learning from 2018. So I think that that matters. I'm going to answer some more of these questions afterwards because I'm almost done with my slides and then we can get into sort of the details. So specifically, and this is kind of like the second part of your questions Brutalel earlier. So there's this comment on the internals form recently like, hey, the roadmap for the year, what things are we actually going to do in 2021. So even though I don't think it matters, should talk a little bit about maybe what I see happening. So this is the text from the original RFC. I'm not going to read all of it, but if you want to go read it, you can. But what we talked about this year is when we prepare for an edition. So the goal should be any changes we make for 2021 are completed by October of 2020. So we should know what's going on. So, you know, it's the end of July right now. So that gives us a couple months, but we should have the plan sort of like in. And also we said like, we've not decided whether we were doing 2020 or not. So we should also decide that we're going to do it. And so like I said, this is my opinion, but technically the project has not decided. So that's also the work to do immediately is and part of deciding to do it is sort of deciding what should be in it too. So there were some things about what might happen in the RFC. We talked about maybe, you know, error handling might be a good thing to address because it's a big topic lately improvements on the trade system or improvements on safe code. But the goal is kind of like to figure out what that is. And so we should have some specifics on exact features kind of soon ish. The language team is at a few discussions on this. And as far as I know, the goal is still to have a specific plan about additions in October. But as I said, we still have to kind of also decide if we even want to do an edition. My audio cut out. Okay. This is not formally done yet. So, you know, we also need to plan that. And so I think that even the stuff that language team is talking about is nothing like 2018. Like the scale is very, very small overall. They're like kind of smaller details about things as an example of one thing that's been talked about. I don't know if this will happen or not or what the chances are even. There's been some discussion that like unsafe functions should have be able to call unsafe code in their bodies without an unsafe block. Or you should need an unsafe block for which order it is. But there's like things like that that are like really tiny edge kind of things and nothing like the module system is being redone. So I think anything that happens in 2021 will be important and matter, but like will be relatively small changes and not like we saw what happened in 2018. There is going to be an RFC on this question of policy. Nico and I were supposed to be working on this, but honestly, I got busy with my new job and Nico did most of the work. So we should have something published relatively soon to answer this question and then we can have this discussion as a community overall because you know it's not the teams do get to decide what they want to decide, but we want feedback from everyone to talk about all the details. So, you know, that kind of matters so you can expect to see an RFC in the near ish future. Talking about the policy of whether we're having an addition or not. And then also the language team, you know, if we decide we're having one language team would be able like what is actually an addition. So that's all going to come over the next few months. So thank you for listening to me talk about that for an hour. That's the end of my presentation and now there's some questions that were in the chat. I definitely want to cover so I'm going to go from the start to the end of the ones that did not answer already. So, okay, there was a question from someone whose name has a lot of numbers and I don't know how to pronounce it I'm sorry. Does it seem reasonable to you to make an addition a snapshot of already shipped features. So keeping features opt in until the next edition while making them shipped and stable as often. I think that's nice in some ways I think that doesn't always work in some other ways. So like what I would sort of like to see is that we have these like features that need an addition break. You're sort of able to opt into the addition on unstable. So it's kind of like that preview idea that happened before so basically like, you know, the feature exists and we're able to try it out on nightly. But you know it's only about tweaking the addition, rather than tweaking all the details. So wherever possible we shouldn't use the addition mechanism like it, making things a breaking change should happen only if they have to. So, you know, talk about the async keyword being a breaking change but I think that like, you know, the union keyword for example was a contextual keyword and we didn't need to do that in addition so we did. We could have and maybe it would have been simpler. But I think that where prefer where we can ship it on all additions we should, and we should only do it like when we actually, you know, need to. So that's, that's the thing that matters. Okay. So, Fred goes to Vester asked a question about why we don't have function overloading so is this historical situation or some design background, kind of not exactly related to my talk other than in theory this is a big feature that would make sense for additions I guess so. I mean one simple example of why rest of that function overloading is no one has ever written an RFC to suggest adding it. Some people have written pre RFCs and some people have done some of the work, but like on its core, most features and rest, you know, don't exist because people didn't do the design work. Now this is a little controversial with this specific feature because like I said some people have gotten up there and I think there's actually an open RFC right now so. Maybe I don't want to say is there's no accepted RFC, but I think that specifically function overloading is interesting because rust does have function overloading today in terms of traits, sort of. So it's not the same as like when you think about, I read a function with different signatures and like you know you figure out that works, but like you can do that through traits, sort of kind of. And that is I think enough for most people that the idea of regular overloading is, you know, a bit too much. I think also this is hard because function overloading, optional arguments and named arguments kind of all are three features that are technically separate, but are something as a language designer you kind of want to consider holistically, and that's a really big design space. And so there's also some people that are interested in this other two features as well. But you kind of really, in my opinion, and I'm not on the Lang team so again this is my personal opinion on this. These are like a large amount of big features that I don't actually think buys you that much personally for me, so I don't really want to see these features added to rust. But that doesn't mean that won't happen like I said, I'm not on the relevant team so my opinion is just contributing as a community member just like anyone else's. But I think it's a huge design space, and I think that most of the benefit is already there. And so I personally don't think that it pulls its weight. One thing I will say on the named arguments front though is with Rust Analyzer putting the names of arguments displayed in the text, I have found them more useful to see that than I would have thought. So it's really made me feel a little better about named arguments than I would have otherwise, but I think that the Rust Analyzer doing that gives you all the benefit without changing the language. So putting a language seems like a lot of work and doesn't really get you a ton of benefits for me personally. Yeah, I think the core challenge is that it's really hard to put all three of those features together and design them all at once. It's a huge space and it's very difficult. So I don't blame anyone that cares about this feature that is put in some of the work. I don't blame anyone that's not made it happen because it's just it's a really big topic and really big area. It's really hard. Okay, so floor B is talking about being in the only make additions happen when there's a need camp. A big part of that is that the social and technical aspect are conflated. Would it make sense to separate them more? The addition is a social event in addition is in cargo.toml. I do think that this is like a coherent point of view, but I just personally disagree. Part of that is because you need the social side to advertise the technical side. They're inherently intertwined. And I know as programmers, we really like to separate out things and we want everything to be kind of in its own little box. But I think that specifically, like with big major changes to the language and ones that are breaking, you're going to have to learn about and stuff. There has to be some sort of social component of letting people know that those things exist. And so like, yeah, you could argue that like we should celebrate what we've done on a different cadence than the release of the actual breaking changes. But like, that just means we have kind of like two major points where we need a bunch of communication. And I think that it all just works better by leaning into the fact that they're actually not separate. I do know that there are some people that feel very strongly that I'm wrong on this and that's also totally fine. Just for me personally, I think that they're not it's not really possible to unwind them and it's actually a good thing that they're together. Because like you need to be able to communicate those things and make it work out. So I don't know. Okay. Jan one Garner says should the six week cycle changes also be listed in the 2021 announcement to be closer to the other language release. So yeah, so what we did, like specifically was that so that blog post that I showed the title of it included the chapter of the changes that were in the things all together. You could argue that maybe they should be like two separate ones. Kind of what we did last time was we blogged before the addition actually happened to kind of talk about what was going to happen. And then the release post was kind of like more of, you know, describing the changes in detail. So it's kind of a way to split that up a little bit. To some degree, I think that when you start to separate it out too much, you get into the exact problem that we're talking about the last question, which is like, I think they need to be around each other because you want to communicate them at the same time. So I do think that including them all in one thing or a small, maybe like in like a month kind of area sort of thing. But yeah, I hope that answers your question. Jack asks, would it be Jack asks to be clear. Would it be another three years till it's available or just available in the next Russi. So like, basically, I think that we should be flexible a little bit about the exact time when we stabilize the addition. Like I don't think we should commit to a specific release because I think that's what introduces like a lot of the problems. It should just be some time in that year. And so I think this is part of also why it's like the Lang team has to have its stuff planned by October of this year, because we want to be able to release it sometime next year. And so if we have stuff done in 2020, then there's a whole year's worth of time to have the schedule happen, rather than trying to, you know, say, OK, we're going to start thinking about this at the beginning of the year, we're going to ship it by the end of the year. Just like if we're ready in advance that that like helps alleviate that schedule pain. Excuse me. Okay, also, oops. Oh, talking too long. Also, wow, okay, guess I just totally lost my voice. Sorry. All right. So also, I think that having the time before things are released matters because putting something in addition that has a breaking change. As I said, it impacts people a lot. So we should do so very carefully. And so I think that one of the sort of like problems of 2018 too was like we had these grand plans. We threw them all in together at the last minute. In some sense, like, we should be more deliberate about what goes in the addition. And therefore we should have to plan it earlier in advance, because that means that we only are willing to do it for things that really, really matter. And so I also think that things should be planned ahead of time because of that. So, yeah, so it should land in Russia at some point during the year of the three years, but I don't think the specifics matter that much. And so another comment on that question was, what does it mean if something, well, audio, there we go. What does it mean if something misses the train? Like say we had a GC, which is not a thing that can happen, as you say, but it missed the train would be another three years. Yeah, so it would have to be another three years unless what missing the train would mean would mean that the stuff that needs to be backwards and compatible would miss the release. So imagine if we did not make async a keyword in 2018, it would have to be a keyword in 2021. And that would mean that like async await couldn't have shipped yet because the time wouldn't have happened. So I think the feature implementation missing the train is totally fine. Like that's what happened with async, right? Like the breaking change made it in, but the implementation didn't happen till later. Great. I think it's totally fine. And in fact, I think is the model that should kind of happen is that like the stuff that is breaking that's not ready yet. We don't worry about making sure that it's actually happened exactly by, you know, the time that really happens. And some of this, I think is because too, it takes time for the ecosystem to catch up. So for example, with async, like async, even if async await had landed on the day of Russ 2018, the ecosystem would not be ready yet. And so for most people, like it's already been almost a year since async await happened, time flies. And the ecosystem is really still only now finally getting into a production ready state. Like async await wasn't really a 2018 feature. It was really a 2021 feature. And so I think that like really a lot of the addition stuff should be looking back over the last three years rather than looking forward to the new stuff. And so like in some sense, the stuff that we reserve in this edition, you know, gets used by folks and like is only really part of Rust World until the future. And I think there's some weird interplay there. And that's also why it's kind of hard to do these kind of bigger macro level changes and thinking about things. So I hope that answers that question. Okay. Angela Feverett says, has been in advances with having a unified async runtime instead of having conflicting runtimes like Tokyo and Actix. So yes and no, like, I think that there's two things that are tied up here. One is that I don't think it's possible to have a unified runtime for everything because Russ is used in too many places. So for example, like, I'm a big fan of both of those projects. But I also do embedded Rust work now. And there's some stuff that maybe would be good as asynchronous. I'm not going to be running Tokyo on like my embedded device. So I would need an embedded executor that makes very different tradeoffs than Tokyo. Tokyo is built for network services specifically. So it's made several tradeoffs to make lots of sense for those things, but it wouldn't make sense for my microcontroller. And the same token, like if I was building a web service, I wouldn't want to use my microcontroller async await in pull because it made the wrong tradeoffs for me. So I think that it's not possible for what what rust is trying to accomplish to have a unified runtime. That said, it should be possible to make libraries run time agnostic. So it doesn't matter what you run time I'm using. And that's like kind of the open things that's still being worked on. And, you know, like, I don't think this is the kind of thing that happens from a big top down perspective. I think that it just takes time in the ecosystem for folks to hash out what they need and what's going on. And we compare experiences and we consolidate where possible. So there hasn't been any big news on that front lately, but like all the people involved are still working on it. And I think everyone cares about making things agnostic, at least conceptually, because nobody wants things to be locked down in a one specific area. So it's just just really tricky. But a lot of a lot of libraries are agnostic today, but not as many as there could be. And there's still more work to do there for sure. All right, another question from League League 11. Is there any intent to sync the addition cycle with major distros and or windows major release cycles, because that might be useful for you know, CentOS, Debian, etc. Not really, because the problem is that all of those things have different cycles and you can't really release them on the same. Like you're going to leave some people out no matter what. So really, we kind of just got to pick our own schedule and just kind of be done with it. And that's sort of unfortunate. I definitely agree with what you're getting at. That would be really nice. But just like, I, it's not really possible, basically. And yeah, I am doing great now. Thank you. It took a while to get out of burnout. So best question. I basically like there's only 15 minutes left and I almost lost my voice, as I said, so still more questions I've not answered. I apologize and not get on to them. But we pretty much don't really have a ton of time. So I'm going to now pick somebody who asked a great question to sort of raffle off the book. So, you know, there's a we're going to leave it sort of that. So let me think here what I think. Let's, let's go with Flora B's question. So I think that it was big and it was on topic with the topic and it was like against what I'm saying, which is always fun, asked in a nice way. And I think that matters. So Flora B on Twitch, you're getting picked as my best question, although I do appreciate all of them. And I believe that means you get a copy of Rust in action. If I remember the details, right? So, so that's cool. The last couple of questions I didn't really get into. Sorry about that. But if you want to email me, I'm happy to talk over email or, you know, whatever else. So thank you so much for listening, everybody. My voice is dying. So I gotta go.
 All right. Hey everybody, I'm Steve. Thanks for coming to my talk. This talk is titled  Should We Have A 2021 Edition? And today is the 27th. So for those of you who don't know,  I am on the core team of Rust. I previously led the documentation team and I wrote the  Rust programming language, which is the introductory book on Rust that comes with Rust itself.  Two other things, though, that you may or may not know, I figured I would mention before  getting to the meat of this talk. I recently got a new job at a company called Oxide Computer  Company. We're building new server computers for people to use. And we're doing like everything  in Rust. So these days, I'm like writing embedded Rust and it's awesome. And we've had an embedded  working group working on it for a while. And I appreciated the work in the abstract sense.  But now that I'm actually doing the work as my job, it's fantastic. So that's pretty cool.  And we are also hiring. So if you are interested in a job where you will write a lot of Rust,  you may want to check that out. Finally, I have started actually working on open source  Rust streaming stuff. So I'm doing my Twitch now. So if you want to watch me program on  Tuesdays, that's the thing I'm doing. Okay. Anyway, enough about me. You want to hear about  additions. So today, we're going to kind of cover these like three major points in this order.  So the first one is what exactly are additions? I want to make sure that we're on the same page  about the details because the details do actually matter and matter a lot here. Secondly, we've  already done sort of one edition release, which is Rust 2018. And so I kind of want to take a  look at that and like kind of how it went and some like thoughts, you know, after some time has  passed. So it's kind of like a little bit of a case study, maybe a little bit of retrospective,  you know, let's like talk about Rust 2018. And then finally, like, what should we actually do?  And this is phrased as should we have Rust 2021? That's kind of like a big thing people have been  talking about lately. I want to sort of emphasize, especially with both of these second sections,  that this is like my personal opinion, while I am on the core team, I am only one person. And,  you know, this is all phrased as like, should we because technically nothing has been decided. So  while I do have my own opinions on this, feel free to disagree and just like, you know, this is  this is me saying this. So take that as far as that goes. All right, so first up this first  section. What even are additions anyway? If you don't know at all, thank you for coming my talk,  even though you don't know the subject. This is exactly why I included this section. But even  if you do, there's some details that maybe some people don't always think about. So I want to talk  about a lot of those details. It's kind of two aspects to additions that I think are really  important. And the first one is the sort of social aspect of Rust. So in addition is kind of this  time point in time where we say, hey, Rust is significantly different now that it was in the  past. And, you know, here's kind of like why. So Rust 1.0 came out in 2015. Rust 2018 was the  first edition sort of release that came out in 2018. And we sort of said like, hey, you know,  Rust has changed a lot in the last three years. You know, let's talk about all the stuff we've  accomplished and add in some other things. And so that's like largely a social thing. So this is  a way to sort of reflect on the longer term progress of the language and the project as a whole.  Because we release every six weeks, that is like a really great thing for a lot of reasons. But  it's really hard to like remember how much work we've done. Releases come out all the time and  they're in small little chunks. And so it can be really, really easy to forget like just how far  long things came. Half the time I forget that it's been like almost five years since Rust 1.0.  Because when things are happening at such a rapid pace, it's really easy to, you know,  lose track of like how far we've come. And so that's like really important. A second one is a  point on like why additions matter are that there are a way to get new users into Rust. So this  sort of is kind of similar to the first point, but a little bit different. Basically, you know,  because we release every six weeks, there's a lot of people who don't pay attention to Rust  releases because they see them so often and they have not that much in them. And so they're kind  of like, you know, hey, you know, I, a new Rust release happens, I don't care. With the languages  that release like once a year or once every couple of years, it's a really big deal. And so a lot of  people will like hear about like, you know, oh, there's a new version of C++ out or there's a  new version of Ruby out or the new C sharp has these cool new things in it. And that's a way for  people who don't currently program in the language to sort of like it signals to them, hey, you know,  I should check this out. Maybe, you know, I looked at C sharp 3.0, and I didn't really like what was  going on. So I didn't use it. Maybe C sharp four, like time for me to check in again, maybe I want  to start programming in it. And so it's kind of a nice way to signal to people outside of the Rust  world as well, that you know, hey, a lot has gone on, and maybe if you didn't use Rust in the past,  you would want to use it again. And then finally, like kind of for actually like development of  Rust, sort of like a nice like rallying cry, I guess, basically, like, you know, not only is about  reflecting on what we've done, but also if there's sort of big things we want to do, it's nice to  build a point in the near future and say, like, you know, hey, it's 2020. Now, we want to do a Rust  2021. And we want to like get people excited. So let's start working on some projects that will  like really generate that excitement. And there's some like back and forth here. And we're going to  talk about all those details in a minute. But it can be a really great way to sort of get everybody  excited about the future of Rust. Because, you know, we like need those check in kind of points, I  think. But also additions are not purely a tech social mechanism, they're also a technical mechanism.  And this this really matters. And so on a technical level, additions are a way to kind of make  breaking changes to the Rust language, without actually making breaking changes. And so how this  kind of works on a technical level is that additions are opt in. So you say what addition your  code is in. And if you don't update that, then you don't update, you know, stuff. So if new things  are added in a way that's like technically breaking, and it doesn't break you, because if you didn't  opt in to the new changes, then your code still works forever. So this is like very different than,  you know, Python two to Python three, for example, where, you know, you can't run your code kind of  like together. And, you know, similar kind of things like that. So we can like make it a way to  opt in to breaking changes. And that's really, really important for compatibility reasons. And  then finally, additions are not allowed to change everything about Rust. This is a technical problem  as much as there's a social problem. And there's some interplay back and forth between the two. But  basically, like, major, major changes are not actually allowed. So some kinds of breaking  changes are fine. But there are some kinds of changes that cannot be made in the addition  mechanism. And that's due to the technical details of how all of this works. It does also kind of a  social thing in the sense that it's also useful for humans, like, if tomorrow, like say Rust 2021  was going to be like garbage collected and use significant white spaces that occurly races, it  would effectively be a whole different language. And that would make it a really big challenge for  people to update to. But because we can only make certain kinds of breaking changes in additions,  it's significantly better for people to be able to upgrade, not only because the opt in nature of  things, but also just like Rust is still going to be Rust, even if there are some tweaks out,  it works. And some changes like the core idea of Rust will be the same. So let's talk a little bit  about what I mean by breaking changes in an addition. So I think one of the best examples of a  breaking change was the async keyword. So Rust has, you know, as I said, two additions right now,  2018 and 2018. And in Rust 2015, code is, you know, async is not a keyword, but in 2018 it is.  And so what that means is, if you look at this code that I have here on the left, we have a  function named async that just takes an integer and returns it. It doesn't do anything fancy. But  we call it passing into five and use underscore s as the name since we never use the variable to get  rid of that kind of warning. So if I run this code on Rust 2018, as you can see, this is the  playpen interface on play.rustlang.org. You can choose this little drop down with the three dots  and then pick which addition you're in. So if you choose Rust 2015, this code will compile and it  runs, doesn't do anything because we just, you know, pass an integer around. So there's no output.  But if we change that to addition 2018, we will get an error. And this will say, expected identifier  found keyword async. So we're allowed to name a function async in Rust 2015 because it's not a  keyword, but we're not allowed to name it in async in Rust 2018 because it is a keyword. So this is  an example of, you know, if we purely made this change in the language, code that existed and ran  just fine before would end up breaking. So this is like a breaking change. But because you can choose  whether or not to upgrade, it's like not a breaking change. And so this kind of like duality, it was  a very controversial around coming up with the plan of additions. And it was also one of the big  challenges of communicating this to users, like technically it's breaking, but it's also not  breaking is very interesting and kind of unusual.  Is my mic still working? All right, cool. Dropped out there for a second. So the way that you opt into  this change, if you're not on the playpen, because most serious Rust programs are not running in the  playpen, that would be ridiculous, is in the cargo.toml. So you get to choose an addition  key by putting 2018 in there. And if this does not exist at all, then it defaults to 2015. So all of the  code that was generated before we had this idea of additions, it is able to, you know, stay on the  sort of the default 2015 edition. But if you opt in, then you're able to do this. And cargo new will  start generating, you know, 2018. So I just typed cargo new to generate this, and it defaults me to  the latest. And so that way, you know, we're able to like new projects start in the latest edition, but older  projects stay on the addition they were created with until their creators explicitly opt in. So that's kind of  like the way that this happens in most real projects. And one thing that's really important, though, about  additions is that additions can interoperate just fine. So let's say that I had packaged up my useless  async function into a crate, and I wanted to use it from some code that was in Rust 2018. Well, one of the  features that was added in Rust 2018 was the ability to use a raw keyword. So I showed you the error  message in the 2018 code before. Right below the error is a little help message that says, hey, you can  escape keywords to use them as identifiers. And so here with this r pound sign, both at the call site and  at the actual declaration site, you're able to still define and call a function named async, even though it's  a keyword. So this would matter if you could imagine that the async function lived in a 2015 crate, then I  would still be able to call it from a 2018 crate. And, you know, vice versa, if there was some other way of doing  it. So this is one example of the ways that code can interoperate. But just in general, like kind of the idea  is that you don't have to be worried about your dependencies at all. Other code is allowed to be in any  addition, and they'll compile into your project just fine. And there's no like worrying about this kind of  interoperability compatibility, other than if, you know, some keywords are named a certain way, and then you  have to know the escape mechanism. But what this means is we don't have the situation whereby when a new  addition comes out, everyone is forced to upgrade all at once, because that doesn't happen. It takes a long  time. And, you know, there's always some people that are going to sort of prefer older things, and we don't  want to like bifurcate the ecosystem. And so this way, these versions can live in total harmony, and your  dependencies can upgrade at their leisure, and you can, you know, upgrade as fast or as slow as you'd like, and  you're not locked out of the rest of us world. So that's a really like helpful way to make sure that all this  operates smoothly. And so specifically, I'd mentioned before, part of the way that this works is that additions  are not allowed to change everything. So these are the rules that were set out in the original RFC, and they're  not complete. So this is not necessarily like a full list of everything that can and can't change. But I wanted  to like point out some specifics. So an example of a thing that can change, as I've already showed you, is new  keywords. So we're allowed to define new keywords and new additions. And, you know, that's totally fine. It's like I  said, they interrupt across the boundary, no problems. The second thing that additions are allowed to change is  allowed to repurpose existing syntax. And I say repurpose because like, you can remove existing syntax, it's like how  it gets repurposed. But like, it generally shouldn't only remove, it should like replace with something that does  something slightly different. So an example of this is, if you have a usage of a trait, in this case, I'm just  calling it trait. But, you know, if you're using this as a trait object, you would just use the name of the trait  originally. So you'd have like box trait or arc trait, something like that. And so what we did in the 2018  edition was we sort of deprecated that usage of just trait on its own. And we introduced dine trait. Unfortunately, my  slides kind of put this on the two lines, normally it would be just one line. But like, this helped you know that hey, this  is a trait object because we're doing dynamic dispatch. And so we kind of like replace that existing syntax for doing a  thing with a new syntax instead. And so you're able to, you know, use this new syntax, and it's like more clear to people  that dynamic dispatch is what's happening. So we're allowed to kind of like, change some existing stuff and add some new  things and like tweak things. Another example of something that changed in the 2018 edition was the module system, which is  a pretty big change. I'll talk about all the changes we made a little bit later. But there's also some things that we can't do.  Earlier I mentioned that we couldn't make really big sweeping changes. But like there's actually slightly more specific  things. Some of them are based on practical limitations, and some of them are based on decisions that we've made. So for  example, the coherence rules can't change across editions. If you're not familiar, a coherence rule says like if a type implements a  trait, is it allowed to implement that trait or not? Like do you get a compiler error when you try to compile a trait  implementation for a type? So, you know, a common example of this rule being broken is that if I had say, a type that's defined  in the standard library like string, and I have a type that's defined in a third party package is not mine, say maybe like  serde, I can't define serde serialize for a string because it's not my trait, it's not my type. So that doesn't work. If I had made  my own string type, then I'd be allowed to implement serde's trait for it. And if I implemented my own trait, I'd be allowed to  implement it on the standard library string. But I have to own either one of the traits or the types. And the rules are a little  more complicated than that. But like that's the gist of it. That's the biggest thing. So that's not allowed to change. We couldn't say  relax them in one addition, but not in the other. And that's because cloh coherence rules are kind of global. And those rules  happen across different crates. So if we had different rules for different parts of your program, that would be extremely hard to  implement, very confusing, and possibly just unsound, like, it's not kind of a thing that you're able to do for all of those  sort of reasons. So, coherence rules have to act globally. And so therefore they kind of have to stay the same in every addition  no matter what. So that's a trick. Secondly, another thing that people sort of don't always appreciate is that we can't make  breaking changes to the standard library. And intuitively, you're like, wait, if I can change crates, standard libraries just  create, like why not? Well, I mean, it is just create, but it's also kind of not just create. You get one copy of the standard  library for your whole program. And so if you had a dependency that used Rust 2018, and then you use Rust 2015, say, then you  would need both copies. So it doesn't like really work that way exactly. So we're able to sort of deprecate things, but we're not  able to remove them. And there's some talk of maybe having some sort of visibility situation where like, they exist, but there's  some visibility rules where this is like only allowed to be seen in 2018, or 2015. Those are proposals and they're not like real  yet. So, you know, this is like kind of half a true technical limitation and half a sort of social limitation. Somebody asked a  question on Twitch. How does a deprecated feature move from deprecated to like removed? And can that be done between  the two versions? So one interesting thing about this is that some of this stuff is kind of up in the air policy wise ish.  Basically, like things cannot actually error on the same edition. So like usually the way you think about it is something that comes a  warning in the old edition, and then an error in the new edition. And the original RFC talks a little bit about code that's  being free on the first edition should compile. Maybe you'll have new warnings, but it won't break on the second edition. But like if  there's warnings in your first edition code, maybe the second edition would break. I'm going to talk a little bit more about this at the  end, because the exact policy is like a thing that we're talking about. So yeah, the rules are slightly up in the air, but  originally that's what the intention was, was that like, you introduce warnings in the first edition, you remove them in the  second edition. There's some questions about whether or not that's like too fast, or maybe we should like require a whole  edition to go by. Like we require language features to wait for a whole release in nightly before we're able to stabilize them,  for example, there's kind of a mandatory minimum waiting period. So maybe there would be a good mandatory waiting period for  deprecations. But yeah, so I hope that answers enough of your question. Hey, Jared. But I'll talk about a little more.  Okay, so why do we have these restrictions, like on some level, like I talked a little bit about some of them with like there's  one crate everywhere. But let's get into some details. And I think this matters because this also really helps you understand  like why certain things are allowed and why certain things aren't allowed. And it's also just kind of fun to talk about the  compiler and how it works. So this next section is going to be about additions, I swear, but it's also kind of how the compiler  works because I think that's interesting and kind of matters. So Rust is currently sort of kind of there's an asterisk here,  I'm going to get to it later, what's called a multi pass compiler. And so this is like a classic architecture for  compilers. If you take a compiler class in your university, this is all the teach you compilers work. A lot of compilers in the  world are implemented this way. Basically what happens is there are this concept of passes. So you can you take in a  source code, and then you spit out something. A lot of older compilers are called one pass compilers because they directly turn the  code into the actual like binary code. So if you think about like used to have to be a lot of older languages required you to  define a variable at the start of functions, for example, that was because they had one pass compilers. And so they needed to  omit the stack space for those variables. Okay, it seems to be back cool. I don't know why that's happening. It's probably something on my  end. But anyway, so yeah, so older compilers are one pass. That's also why a lot of them were super fast, because they didn't do a  lot of this stuff. But over time, you know, we needed things to be more complicated. And so then people develop multi pass  compilers where you would do multiple steps. So you'd iterate over the source code in multiple ways. And that's how it's produced.  So in the Rust compiler, it's like multi pass architecture is traditionally existed. And is similar to many other compilers, basically  of input being source code. And it kind of goes through each of these steps in turn. So the first one takes the source code, and it  creates an AST out of it, which is abstract syntax tree. And then it takes that AST, and it produces here, which is high level IR.  And it takes the high level or IR, and it produces mirror, which is the mid level IR. And it takes the mid level IR, and it  produces MLVM IR, and then LVM takes that and produces the final binary. So there's a bunch of these steps. And within these  steps, there's kind of smaller steps. And all this sort of like happens, we're going to talk about this in a little more detail.  So compilers traditionally are kind of produced in this three different phases. That's why you have these passes, you do the full pass  and the full pass and the full pass, all three steps. First one is like a lexical or syntactic analysis. So is your code well formed?  This is like grammar rules. So, you know, does the sentence I'm saying follow proper grammar or not? Does your program follow the  language as grammar or not? Secondly, is semantic analysis, which does this code make sense? So for example, you know, I could, I could  say like, you know, this sentence is false. And that sentence is grammatically correct. So it passes lexical or syntactic analysis. But  semantically, it's very unclear what it means. Because if it's true, then it's saying it's false, which means it's false, which means  it's not true. So some reflexivity there. It's just the first example I could come up with. But like, you know, you can imagine gibberish,  for example, that uses all real words, maybe it's structurally correct, but it doesn't actually make any sense. So semantic analysis  makes sure that the thing that you've said is sensible. And then finally, code generation, this does not really have an analog in  existing languages. I guess this is the vocal chords turning it into sound. Maybe it would be the analogy, stretching this a little too  far. But once we verify that everything works and makes sense, we actually produce the binary, finally out of it. This step in itself  has a bunch of different passes. For example, we talk about optimization passes, and sort of run and generate code, you know, faster.  So that all happens in this kind of stage. But you know, these are kind of the three big giant steps. If you've ever wondered how  Cargo check works, for example, cargo check will run the lexical and syntactic analysis and the semantic analysis, but won't generate  any code. So this is an example of how understanding this can help you practically as a rest developer, use cargo check to check  your code makes sense. But you don't actually want to run it. You can save yourself a lot of time by not making the compiler do code  generation. So this is like one example of how this architecture lets you do less sometimes. So it's kind of like two sorts of these  steps between these situations. And this is kind of some compiler jargon that you may be interested in. So one of them is called  lowering. And so that's the word that you use when you talk about going from one form to the other. So for example, mere is  lowered into L of the MIR, or the AST is lowered into here. And the reason it's called lowering is that at every step along the  way, things get simpler. And we throw away things that we've already validated, which makes future steps easier. So for example,  MIR does not have the concept of complicated fancy loops. So like for loops, for example, don't exist in MIR. What happens is the previous  steps in the compiler take your for loop and they turn it into a while loop with a break in it. And so MIR is able to understand a  while loop with a break. So we've sort of removed a construct from the language when we've gotten to the lower step. And that  is why the rest of step is simpler. And this definitely really matters. And that's why it's called lowering is because you're kind of  breaking down what is happening into simpler and simpler things. And then finally is a step called a pass, which basically means  a sort of check that validates that your program is well formed. It does not necessarily do a transformation, although technically it can.  So for example, type checking is a pass on your code. So it runs over your code and it makes sure everything makes sense. A lot of  things are kind of passes. And sometimes they will do transformations. This is like whenever basically like, okay, you know, I'm going to take  your for loop and I'm going to rewrite it as a while loop. That happens first as a pass, because inside of here, I believe. And then the  lowering step is what turns that simpler form of here into MIR. So they kind of like work together.  Okay, so this is some example of actual code going through these steps. And I did this about a year ago. So the samples are a little dated  because of the fact that the compiler output changes all the time. But conceptually, it's the same. So I figured it being outdated actually a  little better because you shouldn't get hung up on the specifics. So, for example, let's talk about taking code and producing an AST.  If we have this function called plus one takes 932 adds one to it returns it. We can actually ask the compiler to print out the JSON version  of the AST. Because again, these are all data structures inside the compiler. So they don't really have a text representation, but you can like print them  out and things like JSON. So for example, plus one, a little bit of it looks like this. So there's a statements, and that's an array of nodes.  And inside of there, each node has a variance. So this is like an expression. And then, you know, it's like a binary expression that's add, you  can kind of see how these little bits all fit together. And then, you know, we're adding X, and it keeps going on to talk about adding one  and stuff. So you kind of get this data structure view of your code. And that's what Rust AST looks like. So here, you know, we take our statements  and the statements refers to an expression. Expression refers to a binary expression. The binary expression says, hey, we have an add expression that adds  X and one together. So this is kind of like why it's called a tree is because if you see there's like this root, which is the statements and then there's  the branches and leaves that happen to build a tree. So this is like what an AST kind of looks like visually. And so, yeah, fundamentally, the AST is a data  structure. And it's the way that our code looks written in words, but is a data structure. This means it's easier to manipulate. Like, you know, if you just have a data structure, you can  just manipulate it like that's what they're there for. But if you had to do it on the like textual representation of your code, it would be much harder. So the idea is that we break the text down  into a data structure and then we do all our operations on those data structures. So from the AST, we move on to the here. And so here is short for a high level intermediate  representation. And this basically is like doing form this sort of checks. What I mean by form this is like, you know, have you imported all the stuff that you've used things like that. And some things are  simplified. So for example, in my understanding here does not have, you know, like use statements, they get turned into the elaborated like full versions of all the types. So an example of what, you know, kind of like the sort of transformations that happens here.  This is a very simple for loop. There's a reason I reference for loop several times earlier today, where we take a vector of five integers and we loop over it, printing them all out. So the AST would take that literal code is written and represent it that  way. But when it gets lowered into here, it ends up being something more like this. So this is like still rust code that you could write in theory. But you'll notice the for loop is totally gone. And we now have a loop with a match statement inside. And when we turn the thing that we're  iterating over into an iterator, and we, you know, call next on it repeatedly, until the body of the loop happens and all these things. So you can see how it's kind of like simpler in the sense that there are less language constructs.  It's more complicated in the sense that there's more code. Because like that's the reason we write in the higher level stuff in the first place is because it's easier to understand for humans. But the computer, you know, having less things makes the analysis much simpler.  So we do that kind of stuff.  Most checks in the compiler today are done on here, at least in my understanding.  So here was the original Rust IR that existed. So the first version of the compiler, or maybe first is a little strong, but like for a very long time, the compiler turned everything into here. And then it went to LVM IR from there. So, you know, it's kind of like the og thing. So a lot of things are written in terms of here.  So two things that are still written in type check, or in here are type check, which is like, do all the types make sense and have you not made any type errors. And then finally method lookup. So that's done at compile time instead of in some dynamic languages method lookup is like a dynamic process.  But basically, you know, kind of look at like, you know, what, what trade are you actually calling when you call a method or is there a trade is an inherent method, those kind of things. These are all done on here.  Then we move from here to mirror, and mirror became the subject of a lot of discussion in the Rust world. So you may have heard about it over the last couple years.  Mir is ultimately about control flow. So here is kind of represented our code in the way that we wrote it. But mirror totally rewrites it to be in a simpler form, but also one that's based on a control flow graph is the term, rather than an AST, which is the tree.  So going from a tree to a graph is, you know, helpful for certain kinds of analyses, specifically like the graph represents the way that the control goes through your programs like which statement executes in which order.  And that matters because, for example, non lexical lifetimes, it needs to know how the execution flows within your program to work. And so it was very difficult to write that pass on here.  So like this is a practical example of why this stuff matters is that we had to invent mirror to make non lexical lifetimes feasible, because we needed to be able to encode that flow control to be able to make it actually happen.  And I say we, because I'm on the team, but like I did none of this work to be absolutely clear about it. A lot of other really great people made it happen.  I don't know what's up with my audio dropping. Anyway, so another interesting thing about mirror beyond the control flow move is it's kind of the core of rust. So it's kind of like everything that's rusty about rust without any superfluous extra concepts.  So like I said earlier, fancy loops are gone. Everything is purely loops and breaks. I think I might even have go tos correctly. But Baro checking is done here because, like I said, non lexical lifetimes, kind of mirror is kind of like the core way that, you know, what makes rust rust.  And it's kind of like a representation of the computer of what rust is like.  And as example of what mirror looks like, if you dump out an example, again, this is a little old, and this like pseudo rust is not actually rust code.  But it kind of looks like it again, we're printing a data structure that doesn't have a real text representation.  So here you can see our add one function, it declares two variables zero and two, or one is the first parameter. And in a BB zero stands for basic block. So the pay attention to control flow, we have this idea blocks.  And so it'll say, hey, storage live means that the second variable is live in this area, which is an analysis happens about control flow. It's too complicated for me to get into and I'm too far in the weeds already here.  You can read the docs in the compiler if you want to see all what's happening. You can see our call to add, you know, adds a constant one and our number two, and then declares the storage is dead and then returns.  This kind of what mirror looks like again, not anything you ever have to worry about as a rest programmer but if you want to see all the compiler sees your code, looking at mirror can be really useful.  And then finally, miraget's lowered LLVM IR LLVM is a compiler toolkit that you can use to kind of like build stuff. It's a VM and like the technical sense of VM but not on the way that everyone uses the word VM so you stand for low level virtual machine but the LLVM project  changed its name so that it no longer me references virtual machines because that got too confusing to many people. So basically, what we do is optimizations and code generation are done by LLVM for the most part.  There are a couple optimizations that happen in mirror, and we hope to do more of them in the future, but Russ would not be anywhere where it is today without LLVM so it's very important to us.  And it kind of like is the lowest level of the compiler sort of operates, you know, LLVM takes the compiler's output and produces the binary so we kind of like handed off to that library is the last couple steps.  Andrew Livret, sorry if I mispronounced your name, is asking what is the timeline if there's one to get SIMD support unstable. So SIMD is actually already unstable for Rust, but only the X86 versions so it's also the low level unsafe primitives.  So I think maybe you either one don't know that's true which is totally fine but that does exist today, or two you're talking about higher level SIMD which is like what you would want to write as a regular programmer instead of the intrinsics.  I don't actually know that there's a group working on the higher level stuff right now. The LLVM stuff does work though on X86 at least, and given arms recent interest in Rust, I'm assuming that arm assembly stuff will be soon to follow.  I think maybe some of it already works, but I'm not actually 100% sure. So yeah, still more work to do there. Don't know the exact timeline yet.  Question by jam one Garner. What would go to be used for in mere just more complicated breaks.  Basically like structured programming is useful as the programmer like we write loops because we don't want to have to think it go tos, but go tos are conceptually simpler because they are allowed to do whatever.  And so it's actually easier for the compiler to understand than the higher level constructs. So I actually like I want to emphasize like I don't work on the compiler myself so I believe that go tos exist but I don't actually 100% remember.  So I might be a little wrong there. So you should you know if you care about this topic should look into details a little more, but I believe that that's the case.  But I'm not 100% sure.  Finally, there's a question about working with Rust and fuchsia I will talk about that towards the end because it's not relevant to this part of the conversation so I'll get back to you SpaceX Jedi don't worry about it.  Thank you for the question.  Okay, if you're curious what what LVM IR looks like. This is an example of the text version of LVM IR so you can see that the functions name is mangled so it's add one but with a bunch of other shenanigans on top of it.  And, you know, we add a number to that and return it very straightforward.  There's a whole bunch of attributes and other stuff. So this is kind of like what we hand off to LVM. It does optimization passes there shouldn't be a lot of optimizing to do in this code other than maybe inlining it into other code we've written somewhere else.  So, you know, all that kind of thing.  Okay, the last thing I need to mention on the compiler architecture before we go back to how this manage it how this works with additions I hope you'll forgive my little compiler tutorial here is that I said before we were a multi pass compiler and that's true but we're also like working on making  Rust query based so a lot of the compiler is already query based. And what that means is instead of these kind of passes where you take the whole source code and you turn it into one AST, you take the whole AST turn it into here, vice versa, like you're continuing, you know, down that strategy.  Rust instead uses this concept called a query to create an executable. So what happens instead is the rest compiler will say something like hey what type is this function. What's the body of this function.  And then the compiler will operate in that fashion instead so instead of it being like here's the source code of your program and turn it all into one way.  The compiler will say like give me the you know what where's this function and then the internals the compiler will say oh, we don't have this function yet, but you know, let's load up the source code of what where we you know think it is, and then we'll look at the body and do all that work, and then sort of figure  out that way. And so it'll sort of do all the steps, but in smaller chunks instead. And the reason this is useful is first of all memoization. So you're able to, you know, reuse results of these queries across different invocations of things.  And so that's helpful for compiler speed, but also more importantly it fits increment incremental, incremental compilation can say that incremental compilation it fits it much better.  And so, you know, for able to just say like, Oh, the body of this one function changed that would map directly to one compiler query of saying get me the body of this function. And so then you would only do that part of the work, instead of saying like okay, you  change the body of this function now we have to redo the whole AST and the whole higher level I R and the whole middle level I R. And so this is kind of the way that sort of production grade compilers are written today, rather than the way that they're taught  in the middle. This was started by C sharp with their Roslin compiler so if you're more interested in kind of how this works should look into Roslin or rusty as we continue to make it happen this way.  All the mere stuff is written like this in my understanding, some of the older code is not yet converted but this would kind of be how the stuff sort of works. Also if you've been following rust analyzer lately.  So this is kind of the way that it has this sort of model of like highly incremental and like not traditional architecture that compilers have so that's all how that goes.  Okay, so additions aren't allowed to break everything but like how does that mean, like what's that mean.  So for compilers, basically like additions aren't allowed to differ by the time you get to mirror.  So, you know what that means is a little fuzzy from the outside, basically what it means is the core of rust mere stays the same no matter what. And that really matters for a number of different reasons.  The first thing is that like, because it becomes a common language for all the additions.  It's much easier for the compiler team to sort of manage changes that are brought on by additions. So all of the stuff that happens differences and additions happen earlier stages than mere.  So what that means is we can assume no matter what going forward that mere is like relatively stable obviously the changing the interface but I mean like, we don't have to switch on things by the time you get to that step and so everything is sorted out earlier.  And this happens to make interoperating between additions easier because you know your 2015 code and my 2018 code will both compile into the same mirror at the end so that's how we guarantee interoperability because they're both speaking the same language at the, at the, you know, bottom of it.  Because this is the primary mechanism by which things become interoperable. And it's also the way in which we can like control the amount of breaking changes because if you need something that would change things like very fundamentally, then we can't do it because we need to have this sort of interoperability layer.  On a human side, not being able to break things in mere means that things can change per addition but not that much because like the core understanding of rust and what it is is going to be the same no matter what the sort of like high level details are.  And so that's really important. It also means because we are compiling down at the same thing we have this interoperability when else but the ecosystem and that really matters.  Hey Jared has another question. Would adding more query based compiler features to rust see make rust analyzer and other sort of analyses tools more robust. Yeah, basically that's exactly like the reason that C sharp underwent the Roslin project is IDEs have very different needs for languages than the traditional  compilers do. And so they kind of like reoriented around what happens in an IDE. That's exactly why I phrased it is kind of like, oh I changed the body this function let's not recompile the entire world, because that's what happens when you're actually in your editor programming as you change  little bits. Most of the programs program stays the same. So we kind of want to reuse that work, rather than changing, you know, throwing it all away every single time.  And so yeah, it's definitely one of the reasons why those tools are better is because they want this kind of architecture. So yeah.  Okay. And then another thing about like what is additions towards the end, you kind of think of additions as sort of like a bigger release cycle. So rest already has three different release cycles are stable beta and nightly, and there's different cadences to those releases  so nightly is every night stable and beta happen every six.  Okay, so, you know, additions kind of like our like a bigger release cycle that happens, you know, broader than versions. But we don't have a cadence for additions yet.  This is kind of why this talk exists. And we're working on our FC that I'll get to here at the end, but basically like, we didn't actually decide whether or not this would happen on a schedule or not when we decided to do it in 2018.  So there's no policy in the initial RFC about when additions should be used, as I sort of just mentioned.  It didn't talk about when it just mostly was talking about how. And that way we could focus on shipping rest 2018 and not worry about it until later because, you know, there's a lot of stuff going on.  And we want to set that policy immediately we wanted some experience with additions, we wanted to get it 2018 going and we don't want to think about it basically.  So that's been a couple years time to start thinking about it. So 2018 was sort of the first edition but we kind of retconned it to be the second one so that's 1.0 and that's 2015 where the very first edition sort of speaking.  2018 was the first one that kind of like changed things.  And so what I want to talk about next is like a little look back about how that happened because I think that really informs what we should do in the future.  And this is also again kind of like why we didn't pick a policy back then is we wanted to be able to see how it went and then think about the problem later, rather than trying to invent it beforehand.  So let's talk a little bit about rest 2018 and kind of how it went.  So I think overall rest 2018 was a success.  We achieved our goals, even though it was a ton of work, but we did ship the addition, it did happen.  We managed to understand this was different than rest 2.0 and they didn't like run away thinking that we had totally destroyed our stability guarantees.  Obviously, there were some people that were kind of not happy that we did any sort of changes but you can't please everyone all the time.  But the fact that it was a different kind of mechanism helped people understand what we were trying to accomplish.  And I would say that there are not any real major issues with the addition system itself.  At this point, there's some tweaks and things, but like, you know, the actual rollout of the implementation went smoothly for the most part.  It was a lot of work. It was a really big project for all the teams.  We never really had undertaken such a big project before other than maybe rest 1.0, which is again sort of kind of like an addition.  And so we managed to do it and that's positive and that I think is worth like celebrating.  However, rest 2018 was also not a complete success in my opinion.  So there's kind of two different ways that I think that really struggled.  The first one was the schedule and the second one was the team.  So we didn't ship everything that we wanted to ship in the 2018 edition.  Some things didn't actually get finished. Some things changed significantly and scope had to be cut drastically in order to make it under the release line.  And so while we did ship the mechanism and it was successful, it just barely happened.  The release, as I'm going to talk about schedules in a second, happened in December of 2018.  We actually did not have another Rust release. It happened literally at the last moment.  And so that also is, you know, a sign that things weren't necessarily as ideal as they could have been.  Secondly, it was the human cost of the addition, the team.  Tons of people put in tons of work for a really long time to make this happen.  And it was extremely high stakes because this was a really big thing and it was the first time we'd ever done it.  So that contributed to a lot of burnout amongst contributors, I believe.  I can only truly speak for myself.  I was a total freaking mess by the time the 2018 edition actually happened.  And I wasn't even the one implementing a lot of this stuff.  I was just trying to like keep the book going and do some other work.  So other people worked a lot longer and harder than I did.  And I felt terrible, honestly.  So I can only imagine with other people, you know, how they felt about the schedule.  So we did it, but like at what cost.  And so, yeah, the 2018 edition shipped on December 6th, 2018 with Rust 1.31.  And what's kind of funny about the half shipping thing too is like some actual changes didn't ship until 1.32,  but the addition self-shipped in 1.31.  So, yeah, we shipped a bunch of different things.  This is a screenshot from the blog post.  So non-lexical lifetimes happened in 2018.  Module system changes got simpler in 2018.  We did some more elision stuff.  Constant functions became a thing.  Things like Rust fix got added, a whole bunch of lints like Clippy was able to do its job on stable.  And that was a big deal.  Documentation got updated.  We had the new domain working groups and new website.  Tons of things happened in the standard library.  Lots of new cargo features.  There was just like all sorts of stuff.  Like 2018 was huge.  It's a really big deal.  We shipped a lot of it and that's deserved celebrating.  But as I said, it was behind schedule.  So the initial RFC had sort of this schedule.  There's this idea of a preview period,  which is kind of like you can think about the addition being unstable.  So the idea was that like, okay, Rust 123 is going to start shipping a preview of the addition.  And then in 127, we're going to like nail everything down and actually ship it.  And that'll be when it comes out.  So to put some dates on that,  123 was January 4th in 2018.  And the final 127 release was going to be June 21st, 2018.  So halfway through the year.  And if you're paying attention to a moment earlier,  that was very different than what actually happened.  So what actually happened was the changes landed in the nightly compiler on the 6th of February.  So that was almost one month later than the initial release was planned.  And then finally, the actual release was in December, which is like six months, June to December, something like that.  A long time later.  And we kept thinking it was going to be in like October and then that slipped and then November and then slipped and then December.  We finally got it out the door.  So we almost missed the date itself, which is intense.  I think that this happened because we tried to do too much.  Partially that was because there was a lot of work to do like,  Rust 1.0 was a really small release.  And there was a lot of things that really needed to be tweaked.  We had this opportunity to do it.  So we committed to it and we made it happen.  I think another part of sort of some of the problems was some of these ideas,  we tried to move too far in front of the community.  So like some of the things around, for example, the anonymous lifetime were added.  And I'm not even sure that people like know about the anonymous lifetime or use it exactly because it kind of got lost in the shuffle a little bit.  But we had some ideas about some patterns and they got scaled back and then some things got sort of like cut or barely shipped.  And we tried to like move too far ahead and think about like what things should happen rather than taking what happened and like getting the good parts of it.  There's always a balance to be had there.  I think that added some stress.  The module system was another example of this where we like kind of invented what we wanted and then there's a lot of changes, a lot of feedback.  And it was really, really difficult to get that through.  Finally, the other reason why I think we bit off a little more than we can chew.  So we have, we're really, really great that we have so many contributors to Rust and we did at that time.  But also contributors are not employees.  And it's much harder to plan a big initiative that spans a whole year when you can't be guaranteed that there's like these people that have full time amounts of work to work on it.  Like just from a project management perspective, you know, people are free to come and go as they please on the Rust project.  But that also means that when you're trying to like get a huge thing shipped on a tight deadline, it's difficult to be able to rely on people having the ability to do stuff.  And you know, even if you are an employee, like I said, I got burned out.  I didn't want to do this anymore to some degree.  And so, you know, it can just be really difficult with these kind of big initiatives in an open source world.  I don't think that anyone has figured out how to really accomplish this yet.  Another positive thing was we proved that the mechanism actually worked.  So 2015 and 2018 interoperate just fine.  The plan was good. It happened.  You know, you don't have to worry about this thing.  We can have our cake and eat it too, which is the thing we always try to do in the Rust world.  We didn't split the ecosystem.  There's not a holdout of people that use 2015 that like are sequestered from the rest of the community.  And so that's like really important.  There are still people that program the 2015 edition today and they can do everything they need to do and it works just fine.  So that's I think a really important thing.  We've kept some coherence.  And I think that like it works so well because it's pretty much silent.  Like I don't think most users think about it.  It is just a whole ton, which is part of why I wanted to start this talk by putting out all the details because like it just kind of works.  You normally think about it, I think for most people and that's a testament to how good the thing that we shipped was.  But as a downside, we underestimated the cost of the addition to both the human element, but also to like our users who needed to make these changes happen.  So even though we put a lot of time and effort into making upgrading easy or simple, it wasn't actually so in the end.  And that's just because there's a lot of moving pieces.  So we had Rust fix, which was able to automatically upgrade your code, but like it wasn't perfect.  And there were some things that couldn't necessarily update some of the fancier features and you know, people still have to like validate and test and do these kind of things.  And so it just takes a lot of time.  The compiler did not shift to REST 2018 for a little while.  You did other big projects.  And I think that's also okay, like expecting everyone to upgrade immediately is part of like an unrealistic expectation.  And I don't think we totally had that, but there's definitely some people that thought that should happen overall, like in the community or on the teams, because you know, they worked on smaller projects.  But you know, some production users reported that it took them a while to upgrade to 2018 and it was a significant costly kind of upgrade.  You know, even if it's easy to do, it still takes time and time is money to companies and companies are the ones that have the biggest Rust projects because they're paying people to work on things full time.  And you know, we sort of put a big burden on a lot of our biggest users and that's tough.  So I think that's a challenge.  I think another thing that happened with the 2018 edition is it became feature driven instead of time boxed.  So, you know, normal Rust releases or time box, that is there's a schedule and the release happens, train leaves the station, regardless of whether you make it or not.  And so that's kind of what happened.  And REST 2018 sort of became designed around features.  We sort of said like, hey, what features do we want to happen?  And then we figured out how to make them happen on the schedule.  But then when they took longer to implement, then they took longer to implement them.  Maybe we thought, you know, that became kind of an issue.  And so that was I think a lot of the struggle was like, we need to get these features out and there's this time deadline and we have to have it happen for the time.  That doesn't happen with normal Rust releases because there's always a new train coming in six weeks.  Like part of the reason why we picked the train model in the first place is because we knew that having a yearly or longer release schedule was a problem.  So then we decided with the addition system that we were going to do that.  So I think that was like a big issue.  Kind of felt like lead up to Rust 1.0 where there was this big giant release that happened and everybody worked super hard.  You know, this was a huge amount of hard work and herculean efforts by folks and therefore some burnout happened.  And so I think that that was a big problem with 2018 was getting too caught up in like, it means this set of features and we're going to ship them on this day.  And so a great example of how this did not happen and was very successful is async await.  So, you know, we realized that async await was not going to make it in 2018.  And so we said, hey, we're going to reserve the keyword so that we have it in the addition, but we're not actually going to release the feature.  And so what that meant was that, you know, so 2018 December was when the addition shipped, but we actually shipped the async await in 2019 instead, almost a year later.  And I think that worked out really well.  And it's a great model for how this should sort of work in the future is that we don't necessarily like, you know, do we don't force everything to happen, and we don't force the schedule of the addition to happen on a feature basis.  We kind of say, hey, the future is going to be on this cadence.  And, you know, we're going to ship the feature when it happens.  So that's important.  This is kind of blending into the last part of my talk here, what should we be doing.  So this is kind of like my opinion on where we should go from here.  Basically, we should have a rest 2021 edition.  I know that every talk with a title in it supposed to be no, but the answer is yes.  Gotcha.  Betterages law of headlines.  But I think that we should have a 2021 edition, and we should commit to a train model for additions and we should have one every three years, no matter what.  I think that this should be smaller than Russ 2018 was, for a number of reasons.  First of all, I don't think we have as much need as we did in 2018.  But secondly, like, you know, I think that it will just go smoother if we don't do as much.  And I also think that a lot of people are sort of craving stability in the rest world.  And so I think that that's like a very positive thing.  So a smaller edition would be much smaller than 2018, but I still think we should do it anyway.  There's a question from Emmanuel Lima in the chat.  Does Missila hire engineers to work on Russi and that should help to manage burnout.  No, Missila does pay some people, but it's a very small amount of the overall team.  And there's no indication that Missila is like going to hire 10 more people, which is like what we would need.  So yes, while they could in theory do that, I don't think the Missila is going to.  And I don't always think that just hiring people is always the right solution either, because, you know, it depends.  Like we could hire the community and that'd be great because they already know what's going on.  But that doesn't necessarily mean that's the right call because like not everybody wants to do Russ's their job and like it's complicated basically.  But it's true that work helps diminish burnout, but on some level work can also force you into burnout.  Because when it's your job, you have to do it even if you don't want to.  So like deadlines are somehow weirdly more stressful with jobs than they are with open source projects, I think.  So, you know, like I said, I was a Missila employee at the time of the 2018 edition and I got burned out anyway.  So I don't think it's a pure solution. I do think that can help in some cases.  Yeah. Okay, so release trains like the core of my argument with the 2018 2020 on edition release trains are good and additions are kind of release.  So we should have a train and that should just be the end of it.  Like we should no longer pick date based releases.  We should just always do trains because they're just far better way to ship software.  If six weeks go by without a new release and a new feature in the regular code base, we still put out a new Russ see anyway.  Some additional some releases are small, some additions are big.  You know, that's just the way that it goes.  And so I think that if there's three years go by and we don't need any big breaking changes, it's totally fine.  We should still release a new edition.  Sprutellel asked a question in the chat that I'm going to be getting to very shortly.  So stay tuned.  Yeah, like basically I think the train model has been wonderful.  And I think that we should do it with additions too.  There's a number of reasons I'm not going to get into all of them.  But basically, like the shortest version is it's a model that works and as a model that we've demonstrated is feasible.  So I think we should just do the same thing, but on a longer schedule.  Some people argue that the social part of addition shouldn't matter and that we should only make additions happen when we have the feature need.  But I think that that's wrong.  Some of it is just the classic arguments back and forth that happened the first time the addition happens, like looking over the past three years matters, getting people outside of rust pay attention stuff matters.  And all that stuff still happens.  I think the smaller additions are actually a nicer marketing message.  So shifting them to somehow more important in some ways than a big breaking change release, because it's like, hey, it's been three years with rust and we don't feel the need that there's any big breaking changes because we think the language is good enough.  That is a very strong and powerful marketing.  Message to people to be able to want to check things out.  People are still like leaving comments on the internet all the time about like, I don't know that rust is actually stable because of the six week cadence like people don't necessarily know how much time and effort we put into making sure those things are stable.  And so, you know, every six weeks seems fast.  So people get on the idea of like, oh, I only deal with rust every three years feels better to a large number of people.  So I think that really matters.  So, yeah, there's another question in twitch, I will get to in one second.  So, okay, Spoodle here is your question on a slide.  So what features should be in rust 2021.  I actually don't care personally.  There are some features I want, obviously, but I think that we should do it regardless.  And I don't think that we need to have a specific feature to justify doing an addition.  In fact, I kind of think the argument is stronger purely on the like release engineering and marketing angles and not on the feature based things.  Part of this is also because like consistency and scheduling overall is key.  If we miss something that misses a train, it can get on the next train and that's fine.  But like, if we release additions based on features, and every time we have a new set of features, we have to re litigate this entire conversation.  And we already did it first with 2018 edition and we're doing it now to set up this policy.  And I would like to not sort of like have the rust team be arguing every three years whether or not we should be releasing an addition or not,  but we're arguing like even more often than that.  Like, you know, if we do it on a feature basis, then it happens at random kind of times.  And we just say like, hey, this is the mechanism that happens on this schedule.  Period. Then we can free our time actually working on making rust a better language rather than worrying about this policy.  And so I think that that's actually the sort of most important kind of thing.  I will answer that question, Fred go afterwards.  Why three year cadence. It's just like a nice length of time.  C++ has a three year cadence as of late and yearly is too often because like there's not enough stuff to sort of accumulate to make it a big enough deal every year.  Five years would be far too long in my mind.  So I think three is kind of a nice compromise and it fits similar to C++.  And so I think that that happens.  Specifically, I bring C++ up because C++ OX I think is a cautionary tale that we didn't really learn enough for for the 2018 edition and it feels very similar to the 2018 edition for me.  So the first draft of the standard of C++ was in 2008.  C++ O3 was the previous year of the standard.  And so Bjarn and some other people were hoping that this would be C++ 08 or 09.  So they named it C++ OX.  The problem was that they made it on a feature basis and it took them so many years to get through all the details and ended up shipping in 2011.  And so people used to joke that it was becoming C++ OA because like they had missed like with 08 or 09 scheme it slipped to 10.  So it should be C++ 10, but they had already said OX.  So like, you know, this demonstrates some of this kind of like conflict here.  And so that's when they decided to move to the train model for the C++ releases was like we're releasing every three years because like this was just not great.  And so I think we had a similar kind of learning from 2018.  So I think that that matters.  I'm going to answer some more of these questions afterwards because I'm almost done with my slides and then we can get into sort of the details.  So specifically, and this is kind of like the second part of your questions Brutalel earlier.  So there's this comment on the internals form recently like, hey, the roadmap for the year, what things are we actually going to do in 2021.  So even though I don't think it matters, should talk a little bit about maybe what I see happening.  So this is the text from the original RFC.  I'm not going to read all of it, but if you want to go read it, you can.  But what we talked about this year is when we prepare for an edition.  So the goal should be any changes we make for 2021 are completed by October of 2020.  So we should know what's going on.  So, you know, it's the end of July right now.  So that gives us a couple months, but we should have the plan sort of like in.  And also we said like, we've not decided whether we were doing 2020 or not.  So we should also decide that we're going to do it. And so like I said, this is my opinion, but technically the project has not decided.  So that's also the work to do immediately is and part of deciding to do it is sort of deciding what should be in it too.  So there were some things about what might happen in the RFC.  We talked about maybe, you know, error handling might be a good thing to address because it's a big topic lately improvements on the trade system or improvements on safe code.  But the goal is kind of like to figure out what that is.  And so we should have some specifics on exact features kind of soon ish.  The language team is at a few discussions on this.  And as far as I know, the goal is still to have a specific plan about additions in October.  But as I said, we still have to kind of also decide if we even want to do an edition.  My audio cut out. Okay. This is not formally done yet.  So, you know, we also need to plan that.  And so I think that even the stuff that language team is talking about is nothing like 2018.  Like the scale is very, very small overall.  They're like kind of smaller details about things as an example of one thing that's been talked about.  I don't know if this will happen or not or what the chances are even.  There's been some discussion that like unsafe functions should have be able to call unsafe code in their bodies without an unsafe block.  Or you should need an unsafe block for which order it is.  But there's like things like that that are like really tiny edge kind of things and nothing like the module system is being redone.  So I think anything that happens in 2021 will be important and matter, but like will be relatively small changes and not like we saw what happened in 2018.  There is going to be an RFC on this question of policy.  Nico and I were supposed to be working on this, but honestly, I got busy with my new job and Nico did most of the work.  So we should have something published relatively soon to answer this question and then we can have this discussion as a community overall because you know it's not the teams do get to decide what they want to decide,  but we want feedback from everyone to talk about all the details.  So, you know, that kind of matters so you can expect to see an RFC in the near ish future.  Talking about the policy of whether we're having an addition or not.  And then also the language team, you know, if we decide we're having one language team would be able like what is actually an addition.  So that's all going to come over the next few months.  So thank you for listening to me talk about that for an hour.  That's the end of my presentation and now there's some questions that were in the chat.  I definitely want to cover so I'm going to go from the start to the end of the ones that did not answer already.  So, okay, there was a question from someone whose name has a lot of numbers and I don't know how to pronounce it I'm sorry.  Does it seem reasonable to you to make an addition a snapshot of already shipped features.  So keeping features opt in until the next edition while making them shipped and stable as often.  I think that's nice in some ways I think that doesn't always work in some other ways.  So like what I would sort of like to see is that we have these like features that need an addition break.  You're sort of able to opt into the addition on unstable.  So it's kind of like that preview idea that happened before so basically like, you know, the feature exists and we're able to try it out on nightly.  But you know it's only about tweaking the addition, rather than tweaking all the details.  So wherever possible we shouldn't use the addition mechanism like it, making things a breaking change should happen only if they have to.  So, you know, talk about the async keyword being a breaking change but I think that like, you know, the union keyword for example was a contextual keyword and we didn't need to do that in addition so we did.  We could have and maybe it would have been simpler.  But I think that where prefer where we can ship it on all additions we should, and we should only do it like when we actually, you know, need to. So that's, that's the thing that matters.  Okay.  So, Fred goes to Vester asked a question about why we don't have function overloading so is this historical situation or some design background, kind of not exactly related to my talk other than in theory this is a big feature that would make sense for additions I guess so.  I mean one simple example of why rest of that function overloading is no one has ever written an RFC to suggest adding it.  Some people have written pre RFCs and some people have done some of the work, but like on its core, most features and rest, you know, don't exist because people didn't do the design work.  Now this is a little controversial with this specific feature because like I said some people have gotten up there and I think there's actually an open RFC right now so.  Maybe I don't want to say is there's no accepted RFC, but I think that specifically function overloading is interesting because rust does have function overloading today in terms of traits, sort of.  So it's not the same as like when you think about, I read a function with different signatures and like you know you figure out that works, but like you can do that through traits, sort of kind of.  And that is I think enough for most people that the idea of regular overloading is, you know, a bit too much. I think also this is hard because function overloading, optional arguments and named arguments kind of all are three features that are technically separate,  but are something as a language designer you kind of want to consider holistically, and that's a really big design space.  And so there's also some people that are interested in this other two features as well. But you kind of really, in my opinion, and I'm not on the Lang team so again this is my personal opinion on this.  These are like a large amount of big features that I don't actually think buys you that much personally for me, so I don't really want to see these features added to rust.  But that doesn't mean that won't happen like I said, I'm not on the relevant team so my opinion is just contributing as a community member just like anyone else's.  But I think it's a huge design space, and I think that most of the benefit is already there. And so I personally don't think that it pulls its weight.  One thing I will say on the named arguments front though is with Rust Analyzer putting the names of arguments displayed in the text, I have found them more useful to see that than I would have thought.  So it's really made me feel a little better about named arguments than I would have otherwise, but I think that the Rust Analyzer doing that gives you all the benefit without changing the language.  So putting a language seems like a lot of work and doesn't really get you a ton of benefits for me personally.  Yeah, I think the core challenge is that it's really hard to put all three of those features together and design them all at once.  It's a huge space and it's very difficult. So I don't blame anyone that cares about this feature that is put in some of the work.  I don't blame anyone that's not made it happen because it's just it's a really big topic and really big area. It's really hard.  Okay, so floor B is talking about being in the only make additions happen when there's a need camp.  A big part of that is that the social and technical aspect are conflated. Would it make sense to separate them more?  The addition is a social event in addition is in cargo.toml.  I do think that this is like a coherent point of view, but I just personally disagree.  Part of that is because you need the social side to advertise the technical side.  They're inherently intertwined. And I know as programmers, we really like to separate out things and we want everything to be kind of in its own little box.  But I think that specifically, like with big major changes to the language and ones that are breaking, you're going to have to learn about and stuff.  There has to be some sort of social component of letting people know that those things exist.  And so like, yeah, you could argue that like we should celebrate what we've done on a different cadence than the release of the actual breaking changes.  But like, that just means we have kind of like two major points where we need a bunch of communication.  And I think that it all just works better by leaning into the fact that they're actually not separate.  I do know that there are some people that feel very strongly that I'm wrong on this and that's also totally fine.  Just for me personally, I think that they're not it's not really possible to unwind them and it's actually a good thing that they're together.  Because like you need to be able to communicate those things and make it work out.  So I don't know.  Okay.  Jan one Garner says should the six week cycle changes also be listed in the 2021 announcement to be closer to the other language release.  So yeah, so what we did, like specifically was that so that blog post that I showed the title of it included the chapter of the  changes that were in the things all together.  You could argue that maybe they should be like two separate ones.  Kind of what we did last time was we blogged before the addition actually happened to kind of talk about what was going to happen.  And then the release post was kind of like more of, you know, describing the changes in detail.  So it's kind of a way to split that up a little bit.  To some degree, I think that when you start to separate it out too much, you get into the exact problem that we're talking about the last question,  which is like, I think they need to be around each other because you want to communicate them at the same time.  So I do think that including them all in one thing or a small, maybe like in like a month kind of area sort of thing.  But yeah, I hope that answers your question.  Jack asks, would it be Jack asks to be clear.  Would it be another three years till it's available or just available in the next Russi.  So like, basically, I think that we should be flexible a little bit about the exact time when we stabilize the addition.  Like I don't think we should commit to a specific release because I think that's what introduces like a lot of the problems.  It should just be some time in that year.  And so I think this is part of also why it's like the Lang team has to have its stuff planned by October of this year,  because we want to be able to release it sometime next year.  And so if we have stuff done in 2020, then there's a whole year's worth of time to have the schedule happen,  rather than trying to, you know, say, OK, we're going to start thinking about this at the beginning of the year,  we're going to ship it by the end of the year.  Just like if we're ready in advance that that like helps alleviate that schedule pain.  Excuse me.  Okay, also, oops.  Oh, talking too long.  Also, wow, okay, guess I just totally lost my voice.  Sorry.  All right.  So also, I think that having the time before things are released matters because putting something in addition that has a breaking change.  As I said, it impacts people a lot.  So we should do so very carefully.  And so I think that one of the sort of like problems of 2018 too was like we had these grand plans.  We threw them all in together at the last minute.  In some sense, like, we should be more deliberate about what goes in the addition.  And therefore we should have to plan it earlier in advance, because that means that we only are willing to do it for things that really, really matter.  And so I also think that things should be planned ahead of time because of that.  So, yeah, so it should land in Russia at some point during the year of the three years, but I don't think the specifics matter that much.  And so another comment on that question was, what does it mean if something, well, audio, there we go.  What does it mean if something misses the train?  Like say we had a GC, which is not a thing that can happen, as you say, but it missed the train would be another three years.  Yeah, so it would have to be another three years unless what missing the train would mean would mean that the stuff that needs to be backwards and compatible would miss the release.  So imagine if we did not make async a keyword in 2018, it would have to be a keyword in 2021.  And that would mean that like async await couldn't have shipped yet because the time wouldn't have happened.  So I think the feature implementation missing the train is totally fine.  Like that's what happened with async, right?  Like the breaking change made it in, but the implementation didn't happen till later.  Great. I think it's totally fine.  And in fact, I think is the model that should kind of happen is that like the stuff that is breaking that's not ready yet.  We don't worry about making sure that it's actually happened exactly by, you know, the time that really happens.  And some of this, I think is because too, it takes time for the ecosystem to catch up.  So for example, with async, like async, even if async await had landed on the day of Russ 2018, the ecosystem would not be ready yet.  And so for most people, like it's already been almost a year since async await happened, time flies.  And the ecosystem is really still only now finally getting into a production ready state.  Like async await wasn't really a 2018 feature.  It was really a 2021 feature.  And so I think that like really a lot of the addition stuff should be looking back over the last three years rather than looking forward to the new stuff.  And so like in some sense, the stuff that we reserve in this edition, you know, gets used by folks and like is only really part of Rust World until the future.  And I think there's some weird interplay there.  And that's also why it's kind of hard to do these kind of bigger macro level changes and thinking about things.  So I hope that answers that question.  Okay.  Angela Feverett says, has been in advances with having a unified async runtime instead of having conflicting runtimes like Tokyo and Actix.  So yes and no, like, I think that there's two things that are tied up here.  One is that I don't think it's possible to have a unified runtime for everything because Russ is used in too many places.  So for example, like, I'm a big fan of both of those projects.  But I also do embedded Rust work now.  And there's some stuff that maybe would be good as asynchronous.  I'm not going to be running Tokyo on like my embedded device.  So I would need an embedded executor that makes very different tradeoffs than Tokyo.  Tokyo is built for network services specifically.  So it's made several tradeoffs to make lots of sense for those things, but it wouldn't make sense for my microcontroller.  And the same token, like if I was building a web service, I wouldn't want to use my microcontroller async await in pull because it made the wrong tradeoffs for me.  So I think that it's not possible for what what rust is trying to accomplish to have a unified runtime.  That said, it should be possible to make libraries run time agnostic.  So it doesn't matter what you run time I'm using.  And that's like kind of the open things that's still being worked on.  And, you know, like, I don't think this is the kind of thing that happens from a big top down perspective.  I think that it just takes time in the ecosystem for folks to hash out what they need and what's going on.  And we compare experiences and we consolidate where possible.  So there hasn't been any big news on that front lately, but like all the people involved are still working on it.  And I think everyone cares about making things agnostic, at least conceptually, because nobody wants things to be locked down in a one specific area.  So it's just just really tricky.  But a lot of a lot of libraries are agnostic today, but not as many as there could be.  And there's still more work to do there for sure.  All right, another question from League League 11.  Is there any intent to sync the addition cycle with major distros and or windows major release cycles, because that might be useful for you know, CentOS, Debian, etc.  Not really, because the problem is that all of those things have different cycles and you can't really release them on the same.  Like you're going to leave some people out no matter what.  So really, we kind of just got to pick our own schedule and just kind of be done with it.  And that's sort of unfortunate.  I definitely agree with what you're getting at.  That would be really nice.  But just like, I, it's not really possible, basically.  And yeah, I am doing great now.  Thank you.  It took a while to get out of burnout.  So best question.  I basically like there's only 15 minutes left and I almost lost my voice, as I said, so still more questions I've not answered.  I apologize and not get on to them.  But we pretty much don't really have a ton of time.  So I'm going to now pick somebody who asked a great question to sort of raffle off the book.  So, you know, there's a we're going to leave it sort of that.  So let me think here what I think.  Let's, let's go with Flora B's question.  So I think that it was big and it was on topic with the topic and it was like against what I'm saying, which is always fun, asked in a nice way.  And I think that matters.  So Flora B on Twitch, you're getting picked as my best question, although I do appreciate all of them.  And I believe that means you get a copy of Rust in action.  If I remember the details, right?  So, so that's cool.  The last couple of questions I didn't really get into.  Sorry about that.  But if you want to email me, I'm happy to talk over email or, you know, whatever else.  So thank you so much for listening, everybody.  My voice is dying.  So I gotta go.
Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_0_239.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_240_887.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_888_2039.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_2040_3851.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_3852_4127.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_4128_4271.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_4272_8951.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_8952_11975.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_11976_14627.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_14628_16055.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_16056_18827.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_18828_28307.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_28308_31403.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_31404_34307.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_34308_36971.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_36972_38483.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_38484_39095.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_39096_39707.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_39708_40415.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_40416_41891.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_41892_43139.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_43140_45767.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_45768_47219.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_47220_51203.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_51204_51299.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_51300_51431.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_51432_52079.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_52080_55715.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_55716_59555.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_59556_60599.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_60600_60755.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_60756_61631.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_61632_61763.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_61764_61991.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_61992_62099.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_62100_63515.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_63516_65591.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_65592_65963.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_65964_66023.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_66024_66251.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_66252_66659.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_66660_66851.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_66852_67439.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_67440_67811.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_67812_68615.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_68616_71267.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_71268_72479.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_72480_74423.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_74424_76283.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_76284_77435.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_77436_77591.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_77592_80339.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_80340_81851.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_81852_83591.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_83592_85595.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_85596_86219.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_86220_87923.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_87924_88007.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_88008_88379.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_88380_88511.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_88512_88571.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_88572_88619.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_88620_89291.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_89292_89363.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_89364_89459.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_89460_89639.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_89640_89747.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_89748_92219.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_92220_95879.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_95880_99131.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_99132_101363.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_101364_103007.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_103008_103115.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_103116_103523.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_103524_107003.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_107004_107759.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_107760_107807.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_107808_109259.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_109260_109511.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_109512_110003.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_110004_112007.png Rusty_Days_2020_-_Steve_Klabnik__Should_we_have_a__7LynNMrS8Z0_112008_113297.png
All right. Hey everybody, I'm Steve. Thanks for coming to my talk. This talk is titled Should We Have A 2021 Edition? And today is the 27th. So for those of you who don't know, I am on the core team of Rust. I previously led the documentation team and I wrote the Rust programming language, which is the introductory book on Rust that comes with Rust itself. Two other things, though, that you may or may not know, I figured I would mention before getting to the meat of this talk. I recently got a new job at a company called Oxide Computer Company. We're building new server computers for people to use. And we're doing like everything in Rust. So these days, I'm like writing embedded Rust and it's awesome. And we've had an embedded working group working on it for a while. And I appreciated the work in the abstract sense. But now that I'm actually doing the work as my job, it's fantastic. So that's pretty cool. And we are also hiring. So if you are interested in a job where you will write a lot of Rust, you may want to check that out. Finally, I have started actually working on open source Rust streaming stuff. So I'm doing my Twitch now. So if you want to watch me program on Tuesdays, that's the thing I'm doing. Okay. Anyway, enough about me. You want to hear about additions. So today, we're going to kind of cover these like three major points in this order. So the first one is what exactly are additions? I want to make sure that we're on the same page about the details because the details do actually matter and matter a lot here. Secondly, we've already done sort of one edition release, which is Rust 2018. And so I kind of want to take a look at that and like kind of how it went and some like thoughts, you know, after some time has passed. So it's kind of like a little bit of a case study, maybe a little bit of retrospective, you know, let's like talk about Rust 2018. And then finally, like, what should we actually do? And this is phrased as should we have Rust 2021? That's kind of like a big thing people have been talking about lately. I want to sort of emphasize, especially with both of these second sections, that this is like my personal opinion, while I am on the core team, I am only one person. And, you know, this is all phrased as like, should we because technically nothing has been decided. So while I do have my own opinions on this, feel free to disagree and just like, you know, this is this is me saying this. So take that as far as that goes. All right, so first up this first section. What even are additions anyway? If you don't know at all, thank you for coming my talk, even though you don't know the subject. This is exactly why I included this section. But even if you do, there's some details that maybe some people don't always think about. So I want to talk about a lot of those details. It's kind of two aspects to additions that I think are really important. And the first one is the sort of social aspect of Rust. So in addition is kind of this time point in time where we say, hey, Rust is significantly different now that it was in the past. And, you know, here's kind of like why. So Rust 1.0 came out in 2015. Rust 2018 was the first edition sort of release that came out in 2018. And we sort of said like, hey, you know, Rust has changed a lot in the last three years. You know, let's talk about all the stuff we've accomplished and add in some other things. And so that's like largely a social thing. So this is a way to sort of reflect on the longer term progress of the language and the project as a whole. Because we release every six weeks, that is like a really great thing for a lot of reasons. But it's really hard to like remember how much work we've done. Releases come out all the time and they're in small little chunks. And so it can be really, really easy to forget like just how far long things came. Half the time I forget that it's been like almost five years since Rust 1.0. Because when things are happening at such a rapid pace, it's really easy to, you know, lose track of like how far we've come. And so that's like really important. A second one is a point on like why additions matter are that there are a way to get new users into Rust. So this sort of is kind of similar to the first point, but a little bit different. Basically, you know, because we release every six weeks, there's a lot of people who don't pay attention to Rust releases because they see them so often and they have not that much in them. And so they're kind of like, you know, hey, you know, I, a new Rust release happens, I don't care. With the languages that release like once a year or once every couple of years, it's a really big deal. And so a lot of people will like hear about like, you know, oh, there's a new version of C++ out or there's a new version of Ruby out or the new C sharp has these cool new things in it. And that's a way for people who don't currently program in the language to sort of like it signals to them, hey, you know, I should check this out. Maybe, you know, I looked at C sharp 3.0, and I didn't really like what was going on. So I didn't use it. Maybe C sharp four, like time for me to check in again, maybe I want to start programming in it. And so it's kind of a nice way to signal to people outside of the Rust world as well, that you know, hey, a lot has gone on, and maybe if you didn't use Rust in the past, you would want to use it again. And then finally, like kind of for actually like development of Rust, sort of like a nice like rallying cry, I guess, basically, like, you know, not only is about reflecting on what we've done, but also if there's sort of big things we want to do, it's nice to build a point in the near future and say, like, you know, hey, it's 2020. Now, we want to do a Rust 2021. And we want to like get people excited. So let's start working on some projects that will like really generate that excitement. And there's some like back and forth here. And we're going to talk about all those details in a minute. But it can be a really great way to sort of get everybody excited about the future of Rust. Because, you know, we like need those check in kind of points, I think. But also additions are not purely a tech social mechanism, they're also a technical mechanism. And this this really matters. And so on a technical level, additions are a way to kind of make breaking changes to the Rust language, without actually making breaking changes. And so how this kind of works on a technical level is that additions are opt in. So you say what addition your code is in. And if you don't update that, then you don't update, you know, stuff. So if new things are added in a way that's like technically breaking, and it doesn't break you, because if you didn't opt in to the new changes, then your code still works forever. So this is like very different than, you know, Python two to Python three, for example, where, you know, you can't run your code kind of like together. And, you know, similar kind of things like that. So we can like make it a way to opt in to breaking changes. And that's really, really important for compatibility reasons. And then finally, additions are not allowed to change everything about Rust. This is a technical problem as much as there's a social problem. And there's some interplay back and forth between the two. But basically, like, major, major changes are not actually allowed. So some kinds of breaking changes are fine. But there are some kinds of changes that cannot be made in the addition mechanism. And that's due to the technical details of how all of this works. It does also kind of a social thing in the sense that it's also useful for humans, like, if tomorrow, like say Rust 2021 was going to be like garbage collected and use significant white spaces that occurly races, it would effectively be a whole different language. And that would make it a really big challenge for people to update to. But because we can only make certain kinds of breaking changes in additions, it's significantly better for people to be able to upgrade, not only because the opt in nature of things, but also just like Rust is still going to be Rust, even if there are some tweaks out, it works. And some changes like the core idea of Rust will be the same. So let's talk a little bit about what I mean by breaking changes in an addition. So I think one of the best examples of a breaking change was the async keyword. So Rust has, you know, as I said, two additions right now, 2018 and 2018. And in Rust 2015, code is, you know, async is not a keyword, but in 2018 it is. And so what that means is, if you look at this code that I have here on the left, we have a function named async that just takes an integer and returns it. It doesn't do anything fancy. But we call it passing into five and use underscore s as the name since we never use the variable to get rid of that kind of warning. So if I run this code on Rust 2018, as you can see, this is the playpen interface on play.rustlang.org. You can choose this little drop down with the three dots and then pick which addition you're in. So if you choose Rust 2015, this code will compile and it runs, doesn't do anything because we just, you know, pass an integer around. So there's no output. But if we change that to addition 2018, we will get an error. And this will say, expected identifier found keyword async. So we're allowed to name a function async in Rust 2015 because it's not a keyword, but we're not allowed to name it in async in Rust 2018 because it is a keyword. So this is an example of, you know, if we purely made this change in the language, code that existed and ran just fine before would end up breaking. So this is like a breaking change. But because you can choose whether or not to upgrade, it's like not a breaking change. And so this kind of like duality, it was a very controversial around coming up with the plan of additions. And it was also one of the big challenges of communicating this to users, like technically it's breaking, but it's also not breaking is very interesting and kind of unusual. Is my mic still working? All right, cool. Dropped out there for a second. So the way that you opt into this change, if you're not on the playpen, because most serious Rust programs are not running in the playpen, that would be ridiculous, is in the cargo.toml. So you get to choose an addition key by putting 2018 in there. And if this does not exist at all, then it defaults to 2015. So all of the code that was generated before we had this idea of additions, it is able to, you know, stay on the sort of the default 2015 edition. But if you opt in, then you're able to do this. And cargo new will start generating, you know, 2018. So I just typed cargo new to generate this, and it defaults me to the latest. And so that way, you know, we're able to like new projects start in the latest edition, but older projects stay on the addition they were created with until their creators explicitly opt in. So that's kind of like the way that this happens in most real projects. And one thing that's really important, though, about additions is that additions can interoperate just fine. So let's say that I had packaged up my useless async function into a crate, and I wanted to use it from some code that was in Rust 2018. Well, one of the features that was added in Rust 2018 was the ability to use a raw keyword. So I showed you the error message in the 2018 code before. Right below the error is a little help message that says, hey, you can escape keywords to use them as identifiers. And so here with this r pound sign, both at the call site and at the actual declaration site, you're able to still define and call a function named async, even though it's a keyword. So this would matter if you could imagine that the async function lived in a 2015 crate, then I would still be able to call it from a 2018 crate. And, you know, vice versa, if there was some other way of doing it. So this is one example of the ways that code can interoperate. But just in general, like kind of the idea is that you don't have to be worried about your dependencies at all. Other code is allowed to be in any addition, and they'll compile into your project just fine. And there's no like worrying about this kind of interoperability compatibility, other than if, you know, some keywords are named a certain way, and then you have to know the escape mechanism. But what this means is we don't have the situation whereby when a new addition comes out, everyone is forced to upgrade all at once, because that doesn't happen. It takes a long time. And, you know, there's always some people that are going to sort of prefer older things, and we don't want to like bifurcate the ecosystem. And so this way, these versions can live in total harmony, and your dependencies can upgrade at their leisure, and you can, you know, upgrade as fast or as slow as you'd like, and you're not locked out of the rest of us world. So that's a really like helpful way to make sure that all this operates smoothly. And so specifically, I'd mentioned before, part of the way that this works is that additions are not allowed to change everything. So these are the rules that were set out in the original RFC, and they're not complete. So this is not necessarily like a full list of everything that can and can't change. But I wanted to like point out some specifics. So an example of a thing that can change, as I've already showed you, is new keywords. So we're allowed to define new keywords and new additions. And, you know, that's totally fine. It's like I said, they interrupt across the boundary, no problems. The second thing that additions are allowed to change is allowed to repurpose existing syntax. And I say repurpose because like, you can remove existing syntax, it's like how it gets repurposed. But like, it generally shouldn't only remove, it should like replace with something that does something slightly different. So an example of this is, if you have a usage of a trait, in this case, I'm just calling it trait. But, you know, if you're using this as a trait object, you would just use the name of the trait originally. So you'd have like box trait or arc trait, something like that. And so what we did in the 2018 edition was we sort of deprecated that usage of just trait on its own. And we introduced dine trait. Unfortunately, my slides kind of put this on the two lines, normally it would be just one line. But like, this helped you know that hey, this is a trait object because we're doing dynamic dispatch. And so we kind of like replace that existing syntax for doing a thing with a new syntax instead. And so you're able to, you know, use this new syntax, and it's like more clear to people that dynamic dispatch is what's happening. So we're allowed to kind of like, change some existing stuff and add some new things and like tweak things. Another example of something that changed in the 2018 edition was the module system, which is a pretty big change. I'll talk about all the changes we made a little bit later. But there's also some things that we can't do. Earlier I mentioned that we couldn't make really big sweeping changes. But like there's actually slightly more specific things. Some of them are based on practical limitations, and some of them are based on decisions that we've made. So for example, the coherence rules can't change across editions. If you're not familiar, a coherence rule says like if a type implements a trait, is it allowed to implement that trait or not? Like do you get a compiler error when you try to compile a trait implementation for a type? So, you know, a common example of this rule being broken is that if I had say, a type that's defined in the standard library like string, and I have a type that's defined in a third party package is not mine, say maybe like serde, I can't define serde serialize for a string because it's not my trait, it's not my type. So that doesn't work. If I had made my own string type, then I'd be allowed to implement serde's trait for it. And if I implemented my own trait, I'd be allowed to implement it on the standard library string. But I have to own either one of the traits or the types. And the rules are a little more complicated than that. But like that's the gist of it. That's the biggest thing. So that's not allowed to change. We couldn't say relax them in one addition, but not in the other. And that's because cloh coherence rules are kind of global. And those rules happen across different crates. So if we had different rules for different parts of your program, that would be extremely hard to implement, very confusing, and possibly just unsound, like, it's not kind of a thing that you're able to do for all of those sort of reasons. So, coherence rules have to act globally. And so therefore they kind of have to stay the same in every addition no matter what. So that's a trick. Secondly, another thing that people sort of don't always appreciate is that we can't make breaking changes to the standard library. And intuitively, you're like, wait, if I can change crates, standard libraries just create, like why not? Well, I mean, it is just create, but it's also kind of not just create. You get one copy of the standard library for your whole program. And so if you had a dependency that used Rust 2018, and then you use Rust 2015, say, then you would need both copies. So it doesn't like really work that way exactly. So we're able to sort of deprecate things, but we're not able to remove them. And there's some talk of maybe having some sort of visibility situation where like, they exist, but there's some visibility rules where this is like only allowed to be seen in 2018, or 2015. Those are proposals and they're not like real yet. So, you know, this is like kind of half a true technical limitation and half a sort of social limitation. Somebody asked a question on Twitch. How does a deprecated feature move from deprecated to like removed? And can that be done between the two versions? So one interesting thing about this is that some of this stuff is kind of up in the air policy wise ish. Basically, like things cannot actually error on the same edition. So like usually the way you think about it is something that comes a warning in the old edition, and then an error in the new edition. And the original RFC talks a little bit about code that's being free on the first edition should compile. Maybe you'll have new warnings, but it won't break on the second edition. But like if there's warnings in your first edition code, maybe the second edition would break. I'm going to talk a little bit more about this at the end, because the exact policy is like a thing that we're talking about. So yeah, the rules are slightly up in the air, but originally that's what the intention was, was that like, you introduce warnings in the first edition, you remove them in the second edition. There's some questions about whether or not that's like too fast, or maybe we should like require a whole edition to go by. Like we require language features to wait for a whole release in nightly before we're able to stabilize them, for example, there's kind of a mandatory minimum waiting period. So maybe there would be a good mandatory waiting period for deprecations. But yeah, so I hope that answers enough of your question. Hey, Jared. But I'll talk about a little more. Okay, so why do we have these restrictions, like on some level, like I talked a little bit about some of them with like there's one crate everywhere. But let's get into some details. And I think this matters because this also really helps you understand like why certain things are allowed and why certain things aren't allowed. And it's also just kind of fun to talk about the compiler and how it works. So this next section is going to be about additions, I swear, but it's also kind of how the compiler works because I think that's interesting and kind of matters. So Rust is currently sort of kind of there's an asterisk here, I'm going to get to it later, what's called a multi pass compiler. And so this is like a classic architecture for compilers. If you take a compiler class in your university, this is all the teach you compilers work. A lot of compilers in the world are implemented this way. Basically what happens is there are this concept of passes. So you can you take in a source code, and then you spit out something. A lot of older compilers are called one pass compilers because they directly turn the code into the actual like binary code. So if you think about like used to have to be a lot of older languages required you to define a variable at the start of functions, for example, that was because they had one pass compilers. And so they needed to omit the stack space for those variables. Okay, it seems to be back cool. I don't know why that's happening. It's probably something on my end. But anyway, so yeah, so older compilers are one pass. That's also why a lot of them were super fast, because they didn't do a lot of this stuff. But over time, you know, we needed things to be more complicated. And so then people develop multi pass compilers where you would do multiple steps. So you'd iterate over the source code in multiple ways. And that's how it's produced. So in the Rust compiler, it's like multi pass architecture is traditionally existed. And is similar to many other compilers, basically of input being source code. And it kind of goes through each of these steps in turn. So the first one takes the source code, and it creates an AST out of it, which is abstract syntax tree. And then it takes that AST, and it produces here, which is high level IR. And it takes the high level or IR, and it produces mirror, which is the mid level IR. And it takes the mid level IR, and it produces MLVM IR, and then LVM takes that and produces the final binary. So there's a bunch of these steps. And within these steps, there's kind of smaller steps. And all this sort of like happens, we're going to talk about this in a little more detail. So compilers traditionally are kind of produced in this three different phases. That's why you have these passes, you do the full pass and the full pass and the full pass, all three steps. First one is like a lexical or syntactic analysis. So is your code well formed? This is like grammar rules. So, you know, does the sentence I'm saying follow proper grammar or not? Does your program follow the language as grammar or not? Secondly, is semantic analysis, which does this code make sense? So for example, you know, I could, I could say like, you know, this sentence is false. And that sentence is grammatically correct. So it passes lexical or syntactic analysis. But semantically, it's very unclear what it means. Because if it's true, then it's saying it's false, which means it's false, which means it's not true. So some reflexivity there. It's just the first example I could come up with. But like, you know, you can imagine gibberish, for example, that uses all real words, maybe it's structurally correct, but it doesn't actually make any sense. So semantic analysis makes sure that the thing that you've said is sensible. And then finally, code generation, this does not really have an analog in existing languages. I guess this is the vocal chords turning it into sound. Maybe it would be the analogy, stretching this a little too far. But once we verify that everything works and makes sense, we actually produce the binary, finally out of it. This step in itself has a bunch of different passes. For example, we talk about optimization passes, and sort of run and generate code, you know, faster. So that all happens in this kind of stage. But you know, these are kind of the three big giant steps. If you've ever wondered how Cargo check works, for example, cargo check will run the lexical and syntactic analysis and the semantic analysis, but won't generate any code. So this is an example of how understanding this can help you practically as a rest developer, use cargo check to check your code makes sense. But you don't actually want to run it. You can save yourself a lot of time by not making the compiler do code generation. So this is like one example of how this architecture lets you do less sometimes. So it's kind of like two sorts of these steps between these situations. And this is kind of some compiler jargon that you may be interested in. So one of them is called lowering. And so that's the word that you use when you talk about going from one form to the other. So for example, mere is lowered into L of the MIR, or the AST is lowered into here. And the reason it's called lowering is that at every step along the way, things get simpler. And we throw away things that we've already validated, which makes future steps easier. So for example, MIR does not have the concept of complicated fancy loops. So like for loops, for example, don't exist in MIR. What happens is the previous steps in the compiler take your for loop and they turn it into a while loop with a break in it. And so MIR is able to understand a while loop with a break. So we've sort of removed a construct from the language when we've gotten to the lower step. And that is why the rest of step is simpler. And this definitely really matters. And that's why it's called lowering is because you're kind of breaking down what is happening into simpler and simpler things. And then finally is a step called a pass, which basically means a sort of check that validates that your program is well formed. It does not necessarily do a transformation, although technically it can. So for example, type checking is a pass on your code. So it runs over your code and it makes sure everything makes sense. A lot of things are kind of passes. And sometimes they will do transformations. This is like whenever basically like, okay, you know, I'm going to take your for loop and I'm going to rewrite it as a while loop. That happens first as a pass, because inside of here, I believe. And then the lowering step is what turns that simpler form of here into MIR. So they kind of like work together. Okay, so this is some example of actual code going through these steps. And I did this about a year ago. So the samples are a little dated because of the fact that the compiler output changes all the time. But conceptually, it's the same. So I figured it being outdated actually a little better because you shouldn't get hung up on the specifics. So, for example, let's talk about taking code and producing an AST. If we have this function called plus one takes 932 adds one to it returns it. We can actually ask the compiler to print out the JSON version of the AST. Because again, these are all data structures inside the compiler. So they don't really have a text representation, but you can like print them out and things like JSON. So for example, plus one, a little bit of it looks like this. So there's a statements, and that's an array of nodes. And inside of there, each node has a variance. So this is like an expression. And then, you know, it's like a binary expression that's add, you can kind of see how these little bits all fit together. And then, you know, we're adding X, and it keeps going on to talk about adding one and stuff. So you kind of get this data structure view of your code. And that's what Rust AST looks like. So here, you know, we take our statements and the statements refers to an expression. Expression refers to a binary expression. The binary expression says, hey, we have an add expression that adds X and one together. So this is kind of like why it's called a tree is because if you see there's like this root, which is the statements and then there's the branches and leaves that happen to build a tree. So this is like what an AST kind of looks like visually. And so, yeah, fundamentally, the AST is a data structure. And it's the way that our code looks written in words, but is a data structure. This means it's easier to manipulate. Like, you know, if you just have a data structure, you can just manipulate it like that's what they're there for. But if you had to do it on the like textual representation of your code, it would be much harder. So the idea is that we break the text down into a data structure and then we do all our operations on those data structures. So from the AST, we move on to the here. And so here is short for a high level intermediate representation. And this basically is like doing form this sort of checks. What I mean by form this is like, you know, have you imported all the stuff that you've used things like that. And some things are simplified. So for example, in my understanding here does not have, you know, like use statements, they get turned into the elaborated like full versions of all the types. So an example of what, you know, kind of like the sort of transformations that happens here. This is a very simple for loop. There's a reason I reference for loop several times earlier today, where we take a vector of five integers and we loop over it, printing them all out. So the AST would take that literal code is written and represent it that way. But when it gets lowered into here, it ends up being something more like this. So this is like still rust code that you could write in theory. But you'll notice the for loop is totally gone. And we now have a loop with a match statement inside. And when we turn the thing that we're iterating over into an iterator, and we, you know, call next on it repeatedly, until the body of the loop happens and all these things. So you can see how it's kind of like simpler in the sense that there are less language constructs. It's more complicated in the sense that there's more code. Because like that's the reason we write in the higher level stuff in the first place is because it's easier to understand for humans. But the computer, you know, having less things makes the analysis much simpler. So we do that kind of stuff. Most checks in the compiler today are done on here, at least in my understanding. So here was the original Rust IR that existed. So the first version of the compiler, or maybe first is a little strong, but like for a very long time, the compiler turned everything into here. And then it went to LVM IR from there. So, you know, it's kind of like the og thing. So a lot of things are written in terms of here. So two things that are still written in type check, or in here are type check, which is like, do all the types make sense and have you not made any type errors. And then finally method lookup. So that's done at compile time instead of in some dynamic languages method lookup is like a dynamic process. But basically, you know, kind of look at like, you know, what, what trade are you actually calling when you call a method or is there a trade is an inherent method, those kind of things. These are all done on here. Then we move from here to mirror, and mirror became the subject of a lot of discussion in the Rust world. So you may have heard about it over the last couple years. Mir is ultimately about control flow. So here is kind of represented our code in the way that we wrote it. But mirror totally rewrites it to be in a simpler form, but also one that's based on a control flow graph is the term, rather than an AST, which is the tree. So going from a tree to a graph is, you know, helpful for certain kinds of analyses, specifically like the graph represents the way that the control goes through your programs like which statement executes in which order. And that matters because, for example, non lexical lifetimes, it needs to know how the execution flows within your program to work. And so it was very difficult to write that pass on here. So like this is a practical example of why this stuff matters is that we had to invent mirror to make non lexical lifetimes feasible, because we needed to be able to encode that flow control to be able to make it actually happen. And I say we, because I'm on the team, but like I did none of this work to be absolutely clear about it. A lot of other really great people made it happen. I don't know what's up with my audio dropping. Anyway, so another interesting thing about mirror beyond the control flow move is it's kind of the core of rust. So it's kind of like everything that's rusty about rust without any superfluous extra concepts. So like I said earlier, fancy loops are gone. Everything is purely loops and breaks. I think I might even have go tos correctly. But Baro checking is done here because, like I said, non lexical lifetimes, kind of mirror is kind of like the core way that, you know, what makes rust rust. And it's kind of like a representation of the computer of what rust is like. And as example of what mirror looks like, if you dump out an example, again, this is a little old, and this like pseudo rust is not actually rust code. But it kind of looks like it again, we're printing a data structure that doesn't have a real text representation. So here you can see our add one function, it declares two variables zero and two, or one is the first parameter. And in a BB zero stands for basic block. So the pay attention to control flow, we have this idea blocks. And so it'll say, hey, storage live means that the second variable is live in this area, which is an analysis happens about control flow. It's too complicated for me to get into and I'm too far in the weeds already here. You can read the docs in the compiler if you want to see all what's happening. You can see our call to add, you know, adds a constant one and our number two, and then declares the storage is dead and then returns. This kind of what mirror looks like again, not anything you ever have to worry about as a rest programmer but if you want to see all the compiler sees your code, looking at mirror can be really useful. And then finally, miraget's lowered LLVM IR LLVM is a compiler toolkit that you can use to kind of like build stuff. It's a VM and like the technical sense of VM but not on the way that everyone uses the word VM so you stand for low level virtual machine but the LLVM project changed its name so that it no longer me references virtual machines because that got too confusing to many people. So basically, what we do is optimizations and code generation are done by LLVM for the most part. There are a couple optimizations that happen in mirror, and we hope to do more of them in the future, but Russ would not be anywhere where it is today without LLVM so it's very important to us. And it kind of like is the lowest level of the compiler sort of operates, you know, LLVM takes the compiler's output and produces the binary so we kind of like handed off to that library is the last couple steps. Andrew Livret, sorry if I mispronounced your name, is asking what is the timeline if there's one to get SIMD support unstable. So SIMD is actually already unstable for Rust, but only the X86 versions so it's also the low level unsafe primitives. So I think maybe you either one don't know that's true which is totally fine but that does exist today, or two you're talking about higher level SIMD which is like what you would want to write as a regular programmer instead of the intrinsics. I don't actually know that there's a group working on the higher level stuff right now. The LLVM stuff does work though on X86 at least, and given arms recent interest in Rust, I'm assuming that arm assembly stuff will be soon to follow. I think maybe some of it already works, but I'm not actually 100% sure. So yeah, still more work to do there. Don't know the exact timeline yet. Question by jam one Garner. What would go to be used for in mere just more complicated breaks. Basically like structured programming is useful as the programmer like we write loops because we don't want to have to think it go tos, but go tos are conceptually simpler because they are allowed to do whatever. And so it's actually easier for the compiler to understand than the higher level constructs. So I actually like I want to emphasize like I don't work on the compiler myself so I believe that go tos exist but I don't actually 100% remember. So I might be a little wrong there. So you should you know if you care about this topic should look into details a little more, but I believe that that's the case. But I'm not 100% sure. Finally, there's a question about working with Rust and fuchsia I will talk about that towards the end because it's not relevant to this part of the conversation so I'll get back to you SpaceX Jedi don't worry about it. Thank you for the question. Okay, if you're curious what what LVM IR looks like. This is an example of the text version of LVM IR so you can see that the functions name is mangled so it's add one but with a bunch of other shenanigans on top of it. And, you know, we add a number to that and return it very straightforward. There's a whole bunch of attributes and other stuff. So this is kind of like what we hand off to LVM. It does optimization passes there shouldn't be a lot of optimizing to do in this code other than maybe inlining it into other code we've written somewhere else. So, you know, all that kind of thing. Okay, the last thing I need to mention on the compiler architecture before we go back to how this manage it how this works with additions I hope you'll forgive my little compiler tutorial here is that I said before we were a multi pass compiler and that's true but we're also like working on making Rust query based so a lot of the compiler is already query based. And what that means is instead of these kind of passes where you take the whole source code and you turn it into one AST, you take the whole AST turn it into here, vice versa, like you're continuing, you know, down that strategy. Rust instead uses this concept called a query to create an executable. So what happens instead is the rest compiler will say something like hey what type is this function. What's the body of this function. And then the compiler will operate in that fashion instead so instead of it being like here's the source code of your program and turn it all into one way. The compiler will say like give me the you know what where's this function and then the internals the compiler will say oh, we don't have this function yet, but you know, let's load up the source code of what where we you know think it is, and then we'll look at the body and do all that work, and then sort of figure out that way. And so it'll sort of do all the steps, but in smaller chunks instead. And the reason this is useful is first of all memoization. So you're able to, you know, reuse results of these queries across different invocations of things. And so that's helpful for compiler speed, but also more importantly it fits increment incremental, incremental compilation can say that incremental compilation it fits it much better. And so, you know, for able to just say like, Oh, the body of this one function changed that would map directly to one compiler query of saying get me the body of this function. And so then you would only do that part of the work, instead of saying like okay, you change the body of this function now we have to redo the whole AST and the whole higher level I R and the whole middle level I R. And so this is kind of the way that sort of production grade compilers are written today, rather than the way that they're taught in the middle. This was started by C sharp with their Roslin compiler so if you're more interested in kind of how this works should look into Roslin or rusty as we continue to make it happen this way. All the mere stuff is written like this in my understanding, some of the older code is not yet converted but this would kind of be how the stuff sort of works. Also if you've been following rust analyzer lately. So this is kind of the way that it has this sort of model of like highly incremental and like not traditional architecture that compilers have so that's all how that goes. Okay, so additions aren't allowed to break everything but like how does that mean, like what's that mean. So for compilers, basically like additions aren't allowed to differ by the time you get to mirror. So, you know what that means is a little fuzzy from the outside, basically what it means is the core of rust mere stays the same no matter what. And that really matters for a number of different reasons. The first thing is that like, because it becomes a common language for all the additions. It's much easier for the compiler team to sort of manage changes that are brought on by additions. So all of the stuff that happens differences and additions happen earlier stages than mere. So what that means is we can assume no matter what going forward that mere is like relatively stable obviously the changing the interface but I mean like, we don't have to switch on things by the time you get to that step and so everything is sorted out earlier. And this happens to make interoperating between additions easier because you know your 2015 code and my 2018 code will both compile into the same mirror at the end so that's how we guarantee interoperability because they're both speaking the same language at the, at the, you know, bottom of it. Because this is the primary mechanism by which things become interoperable. And it's also the way in which we can like control the amount of breaking changes because if you need something that would change things like very fundamentally, then we can't do it because we need to have this sort of interoperability layer. On a human side, not being able to break things in mere means that things can change per addition but not that much because like the core understanding of rust and what it is is going to be the same no matter what the sort of like high level details are. And so that's really important. It also means because we are compiling down at the same thing we have this interoperability when else but the ecosystem and that really matters. Hey Jared has another question. Would adding more query based compiler features to rust see make rust analyzer and other sort of analyses tools more robust. Yeah, basically that's exactly like the reason that C sharp underwent the Roslin project is IDEs have very different needs for languages than the traditional compilers do. And so they kind of like reoriented around what happens in an IDE. That's exactly why I phrased it is kind of like, oh I changed the body this function let's not recompile the entire world, because that's what happens when you're actually in your editor programming as you change little bits. Most of the programs program stays the same. So we kind of want to reuse that work, rather than changing, you know, throwing it all away every single time. And so yeah, it's definitely one of the reasons why those tools are better is because they want this kind of architecture. So yeah. Okay. And then another thing about like what is additions towards the end, you kind of think of additions as sort of like a bigger release cycle. So rest already has three different release cycles are stable beta and nightly, and there's different cadences to those releases so nightly is every night stable and beta happen every six. Okay, so, you know, additions kind of like our like a bigger release cycle that happens, you know, broader than versions. But we don't have a cadence for additions yet. This is kind of why this talk exists. And we're working on our FC that I'll get to here at the end, but basically like, we didn't actually decide whether or not this would happen on a schedule or not when we decided to do it in 2018. So there's no policy in the initial RFC about when additions should be used, as I sort of just mentioned. It didn't talk about when it just mostly was talking about how. And that way we could focus on shipping rest 2018 and not worry about it until later because, you know, there's a lot of stuff going on. And we want to set that policy immediately we wanted some experience with additions, we wanted to get it 2018 going and we don't want to think about it basically. So that's been a couple years time to start thinking about it. So 2018 was sort of the first edition but we kind of retconned it to be the second one so that's 1.0 and that's 2015 where the very first edition sort of speaking. 2018 was the first one that kind of like changed things. And so what I want to talk about next is like a little look back about how that happened because I think that really informs what we should do in the future. And this is also again kind of like why we didn't pick a policy back then is we wanted to be able to see how it went and then think about the problem later, rather than trying to invent it beforehand. So let's talk a little bit about rest 2018 and kind of how it went. So I think overall rest 2018 was a success. We achieved our goals, even though it was a ton of work, but we did ship the addition, it did happen. We managed to understand this was different than rest 2.0 and they didn't like run away thinking that we had totally destroyed our stability guarantees. Obviously, there were some people that were kind of not happy that we did any sort of changes but you can't please everyone all the time. But the fact that it was a different kind of mechanism helped people understand what we were trying to accomplish. And I would say that there are not any real major issues with the addition system itself. At this point, there's some tweaks and things, but like, you know, the actual rollout of the implementation went smoothly for the most part. It was a lot of work. It was a really big project for all the teams. We never really had undertaken such a big project before other than maybe rest 1.0, which is again sort of kind of like an addition. And so we managed to do it and that's positive and that I think is worth like celebrating. However, rest 2018 was also not a complete success in my opinion. So there's kind of two different ways that I think that really struggled. The first one was the schedule and the second one was the team. So we didn't ship everything that we wanted to ship in the 2018 edition. Some things didn't actually get finished. Some things changed significantly and scope had to be cut drastically in order to make it under the release line. And so while we did ship the mechanism and it was successful, it just barely happened. The release, as I'm going to talk about schedules in a second, happened in December of 2018. We actually did not have another Rust release. It happened literally at the last moment. And so that also is, you know, a sign that things weren't necessarily as ideal as they could have been. Secondly, it was the human cost of the addition, the team. Tons of people put in tons of work for a really long time to make this happen. And it was extremely high stakes because this was a really big thing and it was the first time we'd ever done it. So that contributed to a lot of burnout amongst contributors, I believe. I can only truly speak for myself. I was a total freaking mess by the time the 2018 edition actually happened. And I wasn't even the one implementing a lot of this stuff. I was just trying to like keep the book going and do some other work. So other people worked a lot longer and harder than I did. And I felt terrible, honestly. So I can only imagine with other people, you know, how they felt about the schedule. So we did it, but like at what cost. And so, yeah, the 2018 edition shipped on December 6th, 2018 with Rust 1.31. And what's kind of funny about the half shipping thing too is like some actual changes didn't ship until 1.32, but the addition self-shipped in 1.31. So, yeah, we shipped a bunch of different things. This is a screenshot from the blog post. So non-lexical lifetimes happened in 2018. Module system changes got simpler in 2018. We did some more elision stuff. Constant functions became a thing. Things like Rust fix got added, a whole bunch of lints like Clippy was able to do its job on stable. And that was a big deal. Documentation got updated. We had the new domain working groups and new website. Tons of things happened in the standard library. Lots of new cargo features. There was just like all sorts of stuff. Like 2018 was huge. It's a really big deal. We shipped a lot of it and that's deserved celebrating. But as I said, it was behind schedule. So the initial RFC had sort of this schedule. There's this idea of a preview period, which is kind of like you can think about the addition being unstable. So the idea was that like, okay, Rust 123 is going to start shipping a preview of the addition. And then in 127, we're going to like nail everything down and actually ship it. And that'll be when it comes out. So to put some dates on that, 123 was January 4th in 2018. And the final 127 release was going to be June 21st, 2018. So halfway through the year. And if you're paying attention to a moment earlier, that was very different than what actually happened. So what actually happened was the changes landed in the nightly compiler on the 6th of February. So that was almost one month later than the initial release was planned. And then finally, the actual release was in December, which is like six months, June to December, something like that. A long time later. And we kept thinking it was going to be in like October and then that slipped and then November and then slipped and then December. We finally got it out the door. So we almost missed the date itself, which is intense. I think that this happened because we tried to do too much. Partially that was because there was a lot of work to do like, Rust 1.0 was a really small release. And there was a lot of things that really needed to be tweaked. We had this opportunity to do it. So we committed to it and we made it happen. I think another part of sort of some of the problems was some of these ideas, we tried to move too far in front of the community. So like some of the things around, for example, the anonymous lifetime were added. And I'm not even sure that people like know about the anonymous lifetime or use it exactly because it kind of got lost in the shuffle a little bit. But we had some ideas about some patterns and they got scaled back and then some things got sort of like cut or barely shipped. And we tried to like move too far ahead and think about like what things should happen rather than taking what happened and like getting the good parts of it. There's always a balance to be had there. I think that added some stress. The module system was another example of this where we like kind of invented what we wanted and then there's a lot of changes, a lot of feedback. And it was really, really difficult to get that through. Finally, the other reason why I think we bit off a little more than we can chew. So we have, we're really, really great that we have so many contributors to Rust and we did at that time. But also contributors are not employees. And it's much harder to plan a big initiative that spans a whole year when you can't be guaranteed that there's like these people that have full time amounts of work to work on it. Like just from a project management perspective, you know, people are free to come and go as they please on the Rust project. But that also means that when you're trying to like get a huge thing shipped on a tight deadline, it's difficult to be able to rely on people having the ability to do stuff. And you know, even if you are an employee, like I said, I got burned out. I didn't want to do this anymore to some degree. And so, you know, it can just be really difficult with these kind of big initiatives in an open source world. I don't think that anyone has figured out how to really accomplish this yet. Another positive thing was we proved that the mechanism actually worked. So 2015 and 2018 interoperate just fine. The plan was good. It happened. You know, you don't have to worry about this thing. We can have our cake and eat it too, which is the thing we always try to do in the Rust world. We didn't split the ecosystem. There's not a holdout of people that use 2015 that like are sequestered from the rest of the community. And so that's like really important. There are still people that program the 2015 edition today and they can do everything they need to do and it works just fine. So that's I think a really important thing. We've kept some coherence. And I think that like it works so well because it's pretty much silent. Like I don't think most users think about it. It is just a whole ton, which is part of why I wanted to start this talk by putting out all the details because like it just kind of works. You normally think about it, I think for most people and that's a testament to how good the thing that we shipped was. But as a downside, we underestimated the cost of the addition to both the human element, but also to like our users who needed to make these changes happen. So even though we put a lot of time and effort into making upgrading easy or simple, it wasn't actually so in the end. And that's just because there's a lot of moving pieces. So we had Rust fix, which was able to automatically upgrade your code, but like it wasn't perfect. And there were some things that couldn't necessarily update some of the fancier features and you know, people still have to like validate and test and do these kind of things. And so it just takes a lot of time. The compiler did not shift to REST 2018 for a little while. You did other big projects. And I think that's also okay, like expecting everyone to upgrade immediately is part of like an unrealistic expectation. And I don't think we totally had that, but there's definitely some people that thought that should happen overall, like in the community or on the teams, because you know, they worked on smaller projects. But you know, some production users reported that it took them a while to upgrade to 2018 and it was a significant costly kind of upgrade. You know, even if it's easy to do, it still takes time and time is money to companies and companies are the ones that have the biggest Rust projects because they're paying people to work on things full time. And you know, we sort of put a big burden on a lot of our biggest users and that's tough. So I think that's a challenge. I think another thing that happened with the 2018 edition is it became feature driven instead of time boxed. So, you know, normal Rust releases or time box, that is there's a schedule and the release happens, train leaves the station, regardless of whether you make it or not. And so that's kind of what happened. And REST 2018 sort of became designed around features. We sort of said like, hey, what features do we want to happen? And then we figured out how to make them happen on the schedule. But then when they took longer to implement, then they took longer to implement them. Maybe we thought, you know, that became kind of an issue. And so that was I think a lot of the struggle was like, we need to get these features out and there's this time deadline and we have to have it happen for the time. That doesn't happen with normal Rust releases because there's always a new train coming in six weeks. Like part of the reason why we picked the train model in the first place is because we knew that having a yearly or longer release schedule was a problem. So then we decided with the addition system that we were going to do that. So I think that was like a big issue. Kind of felt like lead up to Rust 1.0 where there was this big giant release that happened and everybody worked super hard. You know, this was a huge amount of hard work and herculean efforts by folks and therefore some burnout happened. And so I think that that was a big problem with 2018 was getting too caught up in like, it means this set of features and we're going to ship them on this day. And so a great example of how this did not happen and was very successful is async await. So, you know, we realized that async await was not going to make it in 2018. And so we said, hey, we're going to reserve the keyword so that we have it in the addition, but we're not actually going to release the feature. And so what that meant was that, you know, so 2018 December was when the addition shipped, but we actually shipped the async await in 2019 instead, almost a year later. And I think that worked out really well. And it's a great model for how this should sort of work in the future is that we don't necessarily like, you know, do we don't force everything to happen, and we don't force the schedule of the addition to happen on a feature basis. We kind of say, hey, the future is going to be on this cadence. And, you know, we're going to ship the feature when it happens. So that's important. This is kind of blending into the last part of my talk here, what should we be doing. So this is kind of like my opinion on where we should go from here. Basically, we should have a rest 2021 edition. I know that every talk with a title in it supposed to be no, but the answer is yes. Gotcha. Betterages law of headlines. But I think that we should have a 2021 edition, and we should commit to a train model for additions and we should have one every three years, no matter what. I think that this should be smaller than Russ 2018 was, for a number of reasons. First of all, I don't think we have as much need as we did in 2018. But secondly, like, you know, I think that it will just go smoother if we don't do as much. And I also think that a lot of people are sort of craving stability in the rest world. And so I think that that's like a very positive thing. So a smaller edition would be much smaller than 2018, but I still think we should do it anyway. There's a question from Emmanuel Lima in the chat. Does Missila hire engineers to work on Russi and that should help to manage burnout. No, Missila does pay some people, but it's a very small amount of the overall team. And there's no indication that Missila is like going to hire 10 more people, which is like what we would need. So yes, while they could in theory do that, I don't think the Missila is going to. And I don't always think that just hiring people is always the right solution either, because, you know, it depends. Like we could hire the community and that'd be great because they already know what's going on. But that doesn't necessarily mean that's the right call because like not everybody wants to do Russ's their job and like it's complicated basically. But it's true that work helps diminish burnout, but on some level work can also force you into burnout. Because when it's your job, you have to do it even if you don't want to. So like deadlines are somehow weirdly more stressful with jobs than they are with open source projects, I think. So, you know, like I said, I was a Missila employee at the time of the 2018 edition and I got burned out anyway. So I don't think it's a pure solution. I do think that can help in some cases. Yeah. Okay, so release trains like the core of my argument with the 2018 2020 on edition release trains are good and additions are kind of release. So we should have a train and that should just be the end of it. Like we should no longer pick date based releases. We should just always do trains because they're just far better way to ship software. If six weeks go by without a new release and a new feature in the regular code base, we still put out a new Russ see anyway. Some additional some releases are small, some additions are big. You know, that's just the way that it goes. And so I think that if there's three years go by and we don't need any big breaking changes, it's totally fine. We should still release a new edition. Sprutellel asked a question in the chat that I'm going to be getting to very shortly. So stay tuned. Yeah, like basically I think the train model has been wonderful. And I think that we should do it with additions too. There's a number of reasons I'm not going to get into all of them. But basically, like the shortest version is it's a model that works and as a model that we've demonstrated is feasible. So I think we should just do the same thing, but on a longer schedule. Some people argue that the social part of addition shouldn't matter and that we should only make additions happen when we have the feature need. But I think that that's wrong. Some of it is just the classic arguments back and forth that happened the first time the addition happens, like looking over the past three years matters, getting people outside of rust pay attention stuff matters. And all that stuff still happens. I think the smaller additions are actually a nicer marketing message. So shifting them to somehow more important in some ways than a big breaking change release, because it's like, hey, it's been three years with rust and we don't feel the need that there's any big breaking changes because we think the language is good enough. That is a very strong and powerful marketing. Message to people to be able to want to check things out. People are still like leaving comments on the internet all the time about like, I don't know that rust is actually stable because of the six week cadence like people don't necessarily know how much time and effort we put into making sure those things are stable. And so, you know, every six weeks seems fast. So people get on the idea of like, oh, I only deal with rust every three years feels better to a large number of people. So I think that really matters. So, yeah, there's another question in twitch, I will get to in one second. So, okay, Spoodle here is your question on a slide. So what features should be in rust 2021. I actually don't care personally. There are some features I want, obviously, but I think that we should do it regardless. And I don't think that we need to have a specific feature to justify doing an addition. In fact, I kind of think the argument is stronger purely on the like release engineering and marketing angles and not on the feature based things. Part of this is also because like consistency and scheduling overall is key. If we miss something that misses a train, it can get on the next train and that's fine. But like, if we release additions based on features, and every time we have a new set of features, we have to re litigate this entire conversation. And we already did it first with 2018 edition and we're doing it now to set up this policy. And I would like to not sort of like have the rust team be arguing every three years whether or not we should be releasing an addition or not, but we're arguing like even more often than that. Like, you know, if we do it on a feature basis, then it happens at random kind of times. And we just say like, hey, this is the mechanism that happens on this schedule. Period. Then we can free our time actually working on making rust a better language rather than worrying about this policy. And so I think that that's actually the sort of most important kind of thing. I will answer that question, Fred go afterwards. Why three year cadence. It's just like a nice length of time. C++ has a three year cadence as of late and yearly is too often because like there's not enough stuff to sort of accumulate to make it a big enough deal every year. Five years would be far too long in my mind. So I think three is kind of a nice compromise and it fits similar to C++. And so I think that that happens. Specifically, I bring C++ up because C++ OX I think is a cautionary tale that we didn't really learn enough for for the 2018 edition and it feels very similar to the 2018 edition for me. So the first draft of the standard of C++ was in 2008. C++ O3 was the previous year of the standard. And so Bjarn and some other people were hoping that this would be C++ 08 or 09. So they named it C++ OX. The problem was that they made it on a feature basis and it took them so many years to get through all the details and ended up shipping in 2011. And so people used to joke that it was becoming C++ OA because like they had missed like with 08 or 09 scheme it slipped to 10. So it should be C++ 10, but they had already said OX. So like, you know, this demonstrates some of this kind of like conflict here. And so that's when they decided to move to the train model for the C++ releases was like we're releasing every three years because like this was just not great. And so I think we had a similar kind of learning from 2018. So I think that that matters. I'm going to answer some more of these questions afterwards because I'm almost done with my slides and then we can get into sort of the details. So specifically, and this is kind of like the second part of your questions Brutalel earlier. So there's this comment on the internals form recently like, hey, the roadmap for the year, what things are we actually going to do in 2021. So even though I don't think it matters, should talk a little bit about maybe what I see happening. So this is the text from the original RFC. I'm not going to read all of it, but if you want to go read it, you can. But what we talked about this year is when we prepare for an edition. So the goal should be any changes we make for 2021 are completed by October of 2020. So we should know what's going on. So, you know, it's the end of July right now. So that gives us a couple months, but we should have the plan sort of like in. And also we said like, we've not decided whether we were doing 2020 or not. So we should also decide that we're going to do it. And so like I said, this is my opinion, but technically the project has not decided. So that's also the work to do immediately is and part of deciding to do it is sort of deciding what should be in it too. So there were some things about what might happen in the RFC. We talked about maybe, you know, error handling might be a good thing to address because it's a big topic lately improvements on the trade system or improvements on safe code. But the goal is kind of like to figure out what that is. And so we should have some specifics on exact features kind of soon ish. The language team is at a few discussions on this. And as far as I know, the goal is still to have a specific plan about additions in October. But as I said, we still have to kind of also decide if we even want to do an edition. My audio cut out. Okay. This is not formally done yet. So, you know, we also need to plan that. And so I think that even the stuff that language team is talking about is nothing like 2018. Like the scale is very, very small overall. They're like kind of smaller details about things as an example of one thing that's been talked about. I don't know if this will happen or not or what the chances are even. There's been some discussion that like unsafe functions should have be able to call unsafe code in their bodies without an unsafe block. Or you should need an unsafe block for which order it is. But there's like things like that that are like really tiny edge kind of things and nothing like the module system is being redone. So I think anything that happens in 2021 will be important and matter, but like will be relatively small changes and not like we saw what happened in 2018. There is going to be an RFC on this question of policy. Nico and I were supposed to be working on this, but honestly, I got busy with my new job and Nico did most of the work. So we should have something published relatively soon to answer this question and then we can have this discussion as a community overall because you know it's not the teams do get to decide what they want to decide, but we want feedback from everyone to talk about all the details. So, you know, that kind of matters so you can expect to see an RFC in the near ish future. Talking about the policy of whether we're having an addition or not. And then also the language team, you know, if we decide we're having one language team would be able like what is actually an addition. So that's all going to come over the next few months. So thank you for listening to me talk about that for an hour. That's the end of my presentation and now there's some questions that were in the chat. I definitely want to cover so I'm going to go from the start to the end of the ones that did not answer already. So, okay, there was a question from someone whose name has a lot of numbers and I don't know how to pronounce it I'm sorry. Does it seem reasonable to you to make an addition a snapshot of already shipped features. So keeping features opt in until the next edition while making them shipped and stable as often. I think that's nice in some ways I think that doesn't always work in some other ways. So like what I would sort of like to see is that we have these like features that need an addition break. You're sort of able to opt into the addition on unstable. So it's kind of like that preview idea that happened before so basically like, you know, the feature exists and we're able to try it out on nightly. But you know it's only about tweaking the addition, rather than tweaking all the details. So wherever possible we shouldn't use the addition mechanism like it, making things a breaking change should happen only if they have to. So, you know, talk about the async keyword being a breaking change but I think that like, you know, the union keyword for example was a contextual keyword and we didn't need to do that in addition so we did. We could have and maybe it would have been simpler. But I think that where prefer where we can ship it on all additions we should, and we should only do it like when we actually, you know, need to. So that's, that's the thing that matters. Okay. So, Fred goes to Vester asked a question about why we don't have function overloading so is this historical situation or some design background, kind of not exactly related to my talk other than in theory this is a big feature that would make sense for additions I guess so. I mean one simple example of why rest of that function overloading is no one has ever written an RFC to suggest adding it. Some people have written pre RFCs and some people have done some of the work, but like on its core, most features and rest, you know, don't exist because people didn't do the design work. Now this is a little controversial with this specific feature because like I said some people have gotten up there and I think there's actually an open RFC right now so. Maybe I don't want to say is there's no accepted RFC, but I think that specifically function overloading is interesting because rust does have function overloading today in terms of traits, sort of. So it's not the same as like when you think about, I read a function with different signatures and like you know you figure out that works, but like you can do that through traits, sort of kind of. And that is I think enough for most people that the idea of regular overloading is, you know, a bit too much. I think also this is hard because function overloading, optional arguments and named arguments kind of all are three features that are technically separate, but are something as a language designer you kind of want to consider holistically, and that's a really big design space. And so there's also some people that are interested in this other two features as well. But you kind of really, in my opinion, and I'm not on the Lang team so again this is my personal opinion on this. These are like a large amount of big features that I don't actually think buys you that much personally for me, so I don't really want to see these features added to rust. But that doesn't mean that won't happen like I said, I'm not on the relevant team so my opinion is just contributing as a community member just like anyone else's. But I think it's a huge design space, and I think that most of the benefit is already there. And so I personally don't think that it pulls its weight. One thing I will say on the named arguments front though is with Rust Analyzer putting the names of arguments displayed in the text, I have found them more useful to see that than I would have thought. So it's really made me feel a little better about named arguments than I would have otherwise, but I think that the Rust Analyzer doing that gives you all the benefit without changing the language. So putting a language seems like a lot of work and doesn't really get you a ton of benefits for me personally. Yeah, I think the core challenge is that it's really hard to put all three of those features together and design them all at once. It's a huge space and it's very difficult. So I don't blame anyone that cares about this feature that is put in some of the work. I don't blame anyone that's not made it happen because it's just it's a really big topic and really big area. It's really hard. Okay, so floor B is talking about being in the only make additions happen when there's a need camp. A big part of that is that the social and technical aspect are conflated. Would it make sense to separate them more? The addition is a social event in addition is in cargo.toml. I do think that this is like a coherent point of view, but I just personally disagree. Part of that is because you need the social side to advertise the technical side. They're inherently intertwined. And I know as programmers, we really like to separate out things and we want everything to be kind of in its own little box. But I think that specifically, like with big major changes to the language and ones that are breaking, you're going to have to learn about and stuff. There has to be some sort of social component of letting people know that those things exist. And so like, yeah, you could argue that like we should celebrate what we've done on a different cadence than the release of the actual breaking changes. But like, that just means we have kind of like two major points where we need a bunch of communication. And I think that it all just works better by leaning into the fact that they're actually not separate. I do know that there are some people that feel very strongly that I'm wrong on this and that's also totally fine. Just for me personally, I think that they're not it's not really possible to unwind them and it's actually a good thing that they're together. Because like you need to be able to communicate those things and make it work out. So I don't know. Okay. Jan one Garner says should the six week cycle changes also be listed in the 2021 announcement to be closer to the other language release. So yeah, so what we did, like specifically was that so that blog post that I showed the title of it included the chapter of the changes that were in the things all together. You could argue that maybe they should be like two separate ones. Kind of what we did last time was we blogged before the addition actually happened to kind of talk about what was going to happen. And then the release post was kind of like more of, you know, describing the changes in detail. So it's kind of a way to split that up a little bit. To some degree, I think that when you start to separate it out too much, you get into the exact problem that we're talking about the last question, which is like, I think they need to be around each other because you want to communicate them at the same time. So I do think that including them all in one thing or a small, maybe like in like a month kind of area sort of thing. But yeah, I hope that answers your question. Jack asks, would it be Jack asks to be clear. Would it be another three years till it's available or just available in the next Russi. So like, basically, I think that we should be flexible a little bit about the exact time when we stabilize the addition. Like I don't think we should commit to a specific release because I think that's what introduces like a lot of the problems. It should just be some time in that year. And so I think this is part of also why it's like the Lang team has to have its stuff planned by October of this year, because we want to be able to release it sometime next year. And so if we have stuff done in 2020, then there's a whole year's worth of time to have the schedule happen, rather than trying to, you know, say, OK, we're going to start thinking about this at the beginning of the year, we're going to ship it by the end of the year. Just like if we're ready in advance that that like helps alleviate that schedule pain. Excuse me. Okay, also, oops. Oh, talking too long. Also, wow, okay, guess I just totally lost my voice. Sorry. All right. So also, I think that having the time before things are released matters because putting something in addition that has a breaking change. As I said, it impacts people a lot. So we should do so very carefully. And so I think that one of the sort of like problems of 2018 too was like we had these grand plans. We threw them all in together at the last minute. In some sense, like, we should be more deliberate about what goes in the addition. And therefore we should have to plan it earlier in advance, because that means that we only are willing to do it for things that really, really matter. And so I also think that things should be planned ahead of time because of that. So, yeah, so it should land in Russia at some point during the year of the three years, but I don't think the specifics matter that much. And so another comment on that question was, what does it mean if something, well, audio, there we go. What does it mean if something misses the train? Like say we had a GC, which is not a thing that can happen, as you say, but it missed the train would be another three years. Yeah, so it would have to be another three years unless what missing the train would mean would mean that the stuff that needs to be backwards and compatible would miss the release. So imagine if we did not make async a keyword in 2018, it would have to be a keyword in 2021. And that would mean that like async await couldn't have shipped yet because the time wouldn't have happened. So I think the feature implementation missing the train is totally fine. Like that's what happened with async, right? Like the breaking change made it in, but the implementation didn't happen till later. Great. I think it's totally fine. And in fact, I think is the model that should kind of happen is that like the stuff that is breaking that's not ready yet. We don't worry about making sure that it's actually happened exactly by, you know, the time that really happens. And some of this, I think is because too, it takes time for the ecosystem to catch up. So for example, with async, like async, even if async await had landed on the day of Russ 2018, the ecosystem would not be ready yet. And so for most people, like it's already been almost a year since async await happened, time flies. And the ecosystem is really still only now finally getting into a production ready state. Like async await wasn't really a 2018 feature. It was really a 2021 feature. And so I think that like really a lot of the addition stuff should be looking back over the last three years rather than looking forward to the new stuff. And so like in some sense, the stuff that we reserve in this edition, you know, gets used by folks and like is only really part of Rust World until the future. And I think there's some weird interplay there. And that's also why it's kind of hard to do these kind of bigger macro level changes and thinking about things. So I hope that answers that question. Okay. Angela Feverett says, has been in advances with having a unified async runtime instead of having conflicting runtimes like Tokyo and Actix. So yes and no, like, I think that there's two things that are tied up here. One is that I don't think it's possible to have a unified runtime for everything because Russ is used in too many places. So for example, like, I'm a big fan of both of those projects. But I also do embedded Rust work now. And there's some stuff that maybe would be good as asynchronous. I'm not going to be running Tokyo on like my embedded device. So I would need an embedded executor that makes very different tradeoffs than Tokyo. Tokyo is built for network services specifically. So it's made several tradeoffs to make lots of sense for those things, but it wouldn't make sense for my microcontroller. And the same token, like if I was building a web service, I wouldn't want to use my microcontroller async await in pull because it made the wrong tradeoffs for me. So I think that it's not possible for what what rust is trying to accomplish to have a unified runtime. That said, it should be possible to make libraries run time agnostic. So it doesn't matter what you run time I'm using. And that's like kind of the open things that's still being worked on. And, you know, like, I don't think this is the kind of thing that happens from a big top down perspective. I think that it just takes time in the ecosystem for folks to hash out what they need and what's going on. And we compare experiences and we consolidate where possible. So there hasn't been any big news on that front lately, but like all the people involved are still working on it. And I think everyone cares about making things agnostic, at least conceptually, because nobody wants things to be locked down in a one specific area. So it's just just really tricky. But a lot of a lot of libraries are agnostic today, but not as many as there could be. And there's still more work to do there for sure. All right, another question from League League 11. Is there any intent to sync the addition cycle with major distros and or windows major release cycles, because that might be useful for you know, CentOS, Debian, etc. Not really, because the problem is that all of those things have different cycles and you can't really release them on the same. Like you're going to leave some people out no matter what. So really, we kind of just got to pick our own schedule and just kind of be done with it. And that's sort of unfortunate. I definitely agree with what you're getting at. That would be really nice. But just like, I, it's not really possible, basically. And yeah, I am doing great now. Thank you. It took a while to get out of burnout. So best question. I basically like there's only 15 minutes left and I almost lost my voice, as I said, so still more questions I've not answered. I apologize and not get on to them. But we pretty much don't really have a ton of time. So I'm going to now pick somebody who asked a great question to sort of raffle off the book. So, you know, there's a we're going to leave it sort of that. So let me think here what I think. Let's, let's go with Flora B's question. So I think that it was big and it was on topic with the topic and it was like against what I'm saying, which is always fun, asked in a nice way. And I think that matters. So Flora B on Twitch, you're getting picked as my best question, although I do appreciate all of them. And I believe that means you get a copy of Rust in action. If I remember the details, right? So, so that's cool. The last couple of questions I didn't really get into. Sorry about that. But if you want to email me, I'm happy to talk over email or, you know, whatever else. So thank you so much for listening, everybody. My voice is dying. So I gotta go.
know, let's like talk about Rust 2018. And then people outside of the Rust world as well, that and how it works. So this next section is going what actually happened. So what actually happened what things are we actually going to do in 2021. an edition. My audio cut out. Okay. This is not to answer this question and then we can have this release of the actual breaking changes. But like, that feel very strongly that I'm wrong on this about this at the beginning of the year, we're the three years, but I don't think the specifics