CppCast - Safe, Borrow-Checked, C++

Episode Date: May 31, 2024

Sean Baxter joins Timur and Phil. Sean explains how he has managed to implement a borrow checker for C++ in his Circle compiler. In fact his implementation addresses all the same safety issues that Ru...st addresses. News "Noisy: The Class You Wrote a Hundred Times" Reddit discussion "Addressing That Post About final" Conference News: Pure Virtual C++ 2024 videos C++ on Sea 2024 - full scheduled published Links Jet Propulsion Lab Circle homepage "Safe C++" - Sean's video covering the implementation discussed on the episode P2687R0 - "Design Alternatives for Type-and-Resource Safe C++" - Stroustrup & Dos Reis P2771R0 - "Towards memory safety in C++" Clang's "Lifetime Extensions for C++" RFC

Transcript
Discussion (0)
Starting point is 00:00:00 Episode 383 of CppCast with guest Sean Baxter, recorded 17th of May 2024. In this episode, we talk about the noisy class, an update on the final keyword, and some conference news. Then we are joined by Sean Baxter. Sean talks to us about how to add, the first podcast for C++ developers by C++ developers. I'm your host, Timo Dummler, joined by my co-host, Phil Nash. Phil, how are you doing today?
Starting point is 00:01:02 I'm all right, Timo. How are you doing? I'm all right, Phil. I'm a bit sleep-depri deprived, but to make up for it, the weather is really nice. It's actually quite hot, actually hotter than in the rest of Europe, actually, apparently. So the Finnish summer has started properly now. So it's good stuff. How are you doing? How are your preparations for SwiftCraft going? Still stressful, but we're getting there now we're actually recording this the same week as the previous episode just because of our travel plans coming up so i'm still stressing about my new swift conference next week okay so at the top
Starting point is 00:01:35 of every episode we'd like to read a piece of feedback but because we're recording this uh three days after we recorded the last episode because fit and i are gonna travel next week um we didn't actually receive any feedback in those few days so keep sending us feedback we'd like to hear thoughts about the show and you can always reach out to us on x mustard on linkedin or email us at feedback at cppcast.com joining us today is sean baxter sean is the author of the circle c++ compiler it's a one-man effort to build the memory-safe C++ toolchain of the future. In another age, he worked at DE Shore Research, NVIDIA Research, and Jet Propulsion Lab. Sean, welcome to the show. Thank you. Good morning. Thanks for inviting me on.
Starting point is 00:02:16 Sean, we're still going to talk about Circle in a bit in the interview, but you mentioned you worked at Jet Propulsion Lab previously. That's part of NASA, isn't it? Yeah, it's the lab that's operated by Caltech. It's in Pasadena, and it's owned by NASA. I worked in the Earth Science Division doing remote sensing, so satellite imaging of the planet. All right. So did you have any involvement in any of the well-known projects
Starting point is 00:02:43 like the Curiosity rover or anything like that? No, it was more like instruments on now very antiquated satellites. But I remember it was kind of when the James Webb Space Telescope was being brought up. So that was the big flagship project for the whole NASA administration. Excellent. It's funny you mentioned satellites. We had a guest on mark gillard i
Starting point is 00:03:05 think it was 10 episodes ago or something uh who lives here in helsinki and we kind of hang out and he took me to his place where he works and that's a satellite company too so and they were like showing me like the actual satellites and like that was really cool um so apparently there's quite a few places doing these kind of stuff and it's all C++. Or maybe not. I don't know. What were you doing back then? I was doing like ground systems. So I wasn't writing code that runs on the device.
Starting point is 00:03:31 That was all like, that was a different world. That was like very formal verification. Okay. Okay. Okay. Interesting. Interesting. So we'll get more into your work in a few minutes, but first we have a couple of news
Starting point is 00:03:43 articles to talk about. So feel free to comment any of these. The first one is, again, we're recording this three days after the last episode. So we don't have a spectacular amount of news items now. But I found a few things that I found interesting. One of them is the so-called noisy class, which is a class that you probably wrote 100 hundred times by vincent salzow it's on github uh there's a blog post there's a reddit uh thread it's basically this thing that you write when you test something or like every special member function like constructor destructor copy
Starting point is 00:04:15 constructor etc just prints you know i am the constructor i've been called or whatever and like every object gets like its own id so you can track how many instances there are and stuff like that and there's somebody who just implemented that kind of properly and put that on github and that's probably very useful for testing and debugging and all kinds of other stuff so as always people are asking on the red thread for a bunch of additional stuff somebody says oh well it needs to be thread safe but like yeah what does that mean per thread counters global atomic counter something else is is the shared pointer thread safe like depends on how you define that right yeah and then like
Starting point is 00:04:51 it needs to have a value but okay you can just write a struct with the value and a noisy in it so i guess there's a workaround there but like yeah people are asking for more stuff but the basic thing is there i think it's very useful um for all kinds of testing yeah i've written the same thing many times myself i'm sure a lot of people have but the last time i did that was for my co-routines talk a couple of years ago where i needed to you know test when objects were were created and destroyed in the context of co-routines which is actually a lot a lot different to normal lifetimes yeah yeah yeah i'm doing this for example when I'm trying to figure out what an STL algorithm does and how many times it moves things around
Starting point is 00:05:28 and, you know, things like that. But there's lots of use cases for it. So, you know, next time you can just grab it from Vincent, which is on GitHub. Right. So the second thing that I have today is we had, again, a couple episodes ago, we talked about the blog post by Ben
Starting point is 00:05:46 about the performance impact of the final keyword. And apparently that blog post got quite a lot of response, some of it positive, some of it negative, some of it with follow-up questions. So Ben actually now published a follow-up post addressing some of those questions and concerns that have been raised over the original post and i found that interesting yeah i did say at the time that probably wasn't the final word it definitely wasn't all right so to wrap up our news section
Starting point is 00:06:17 we have a few conference news uh we had sybrand on again a few episodes ago um who was promoting their uh pure virtual c++ conference which is really amazing it's run by microsoft it's a brand on again a few episodes ago who was promoting their Pure Virtual C++ conference, which is really amazing. It's run by Microsoft. It's a free online conference that anybody can just attend and you get great talks, live talks about C++. And so that conference is over, but now the recordings
Starting point is 00:06:37 are available and they're also available for free on YouTube, which is pretty awesome. It does include that talk from Sai about how they embedded a programming language into a debug information file. So if you want to find out about that, you can now watch that on YouTube. Great. And the last conference news I have here is, Phil,
Starting point is 00:06:57 one of your conferences, CPP on C, which is happening next month, if I'm not mistaken, and you now published a schedule. Do you want to talk to us about that yes well um i mean as we record this now it's it's not next month it's in july but uh by the time this is published but uh yeah the schedule has been released i should have mentioned that last time uh so we're now like a couple of weeks in but uh really packed schedule it's going to be the biggest c++ on c yet so four four tracks over three days and two day workshops we've even got an additional movie night hosted by walter brown
Starting point is 00:07:33 on the wednesday evening i believe so yep there's going to be content you know morning till night pretty much every day so now is the time to go get your tickets of course it's an amazing conference i i'm i'm i have to admit that unfortunately unfortunately this year i i cannot make it i have a little bit of a family event uh going on at the same time so i i cannot attend but it's a shame because it's one of my favorite conferences is always great and i will definitely be there again next year yeah you're excused this time but i do expect you back the next time you can count on it yeah you did a great talk last year on safety and c++ which i think sean might even be mentioning today yeah so so that has been a hot topic in
Starting point is 00:08:21 our community i think for the last couple years actually uh there was this push from various government agencies towards memory-safe languages, and they were saying, you know, we should all basically move away from CNC or SUS because they're not safe. They have all of these memory-safety-related undefined behavior vulnerabilities and all of that stuff. And what caught our attention this week is that Sean actually made a very bold claim on social media. Sean is saying that he has solved the safety problem in C++.
Starting point is 00:08:53 And one of the things that I think said last year when I did a talk about this is that I don't think you can really do it. I think at the time, Sean, you had a tweet where you said, I'm going to implement a borrow checker in C++ and show you all that you can solve the problem. do it uh i think at the time sean you had a tweet where you said i'm gonna like i'm gonna implement a borrow checker and c plus dash and show you all that you can solve the problem i was like yeah i believe it when i see it but now you actually did it so um you know we thought like we must get you on the show and talk about that you actually have a youtube video um about how it all works uh which
Starting point is 00:09:20 i watched uh bill i think you as well right i've watched half of it so far. It's really good stuff. It's really fascinating. So yeah, we're going to put the link to that in the show notes. But yeah, we want to talk to you about that. We had a number of successor languages actually here or like so-called successor languages, languages that somebody somewhere called
Starting point is 00:09:40 potential successor languages for C++. We had people who work on these languages here on the show in the context of safety and how these languages are safer than C++. So we had Richard Smith talk about Carbon. We had an episode about Val, which is I think now called Hylo. We had an episode about CPP2.
Starting point is 00:09:59 With Herb, we had an episode about Rust just last time. We had Mara on. We also talked to Piana about safety. So it was a topic that we spent a lot of time on the show talking about, but we haven't actually considered Circle in this context. So
Starting point is 00:10:15 I just looked it up the last time, Sean, you were on the show. It was actually January 2020. So it was like way before Phil and I took over. And I don't think the whole safety thing was quite as much in focus back then as it is now. So we have a lot of new stuff to talk about. But before we do that, can you just quickly remind us what is Circle? Sure.
Starting point is 00:10:34 This is a project I started almost eight years ago, if you believe that. My initial impetus was to create a compiler where you could run any code at compile time. So you could write a normal function and execute it in an interpreter and open files and do like really aggressive metaprogramming. And it just became a platform for experimentation. So up until the present, I embedded like a shader language into it, really advanced pack declarations. But for the last two years, I've kind of been pursuing memory safety. And since I wrote the compiler from scratch, I know where everything is, I've been able to kind of replace the object model and aggressively expand the type system.
Starting point is 00:11:19 And this is possible because I wrote this compiler really for another purpose. It has become kind of a tool bench for experimenting with lots of features. That sounds really cool. So I have a question though. So some of our work has been going on for a while where people were essentially trying to like add extensions to C++ or things on top of C++, not necessarily other languages,
Starting point is 00:11:40 but C++ specifically, which I think kind of is what Circle is doing. It kind of extends C++, right? Rather than doing something else. So people have been doing extensions like this for a while. I think Microsoft did a lot of work in that area. Like they had these lifetime annotations for a while. Visual Studio has this like a lifetime profile checker.
Starting point is 00:11:58 I think Herb was giving talks about this way back, like 10 years ago or something already. Pianos, TrueStrip and Gabriel Dos Reis have this ongoing work about doing static analysis on C++ to basically based on the core guidelines
Starting point is 00:12:14 to statically find violations of those core guidelines and dangling pointers and dangling references and things like that. There's Thomas Neumann's work on adding a lifetime annotation to standard C++. There's Cl Neumann's work on lifetime, adding lifetime annotations to standard C++. There's Clang, which is working on lifetime annotations and adding them into their compiler.
Starting point is 00:12:31 So there's a lot of work going on there. How is your stuff different from this? Well, you have to ask yourself what the goal of your work is. And all the government warnings and the corporate warnings coming out over the last couple of years has been to achieve rigorous memory safety, where you create a safe subset of a language, and it's not possible to inadvertently or even intentionally write language undefined behaviors. And these other efforts, these other, like the Microsoft lifetime annotations, they don't prevent undefined behaviors. They are static analysis passes that may catch some misuses, but they don't ensure
Starting point is 00:13:15 safety. So they don't, they're not really solving the problem of moving C++ to a system that it's just safe to write code in. They're heuristics and they're not like safe by design. Right. But they do use kind of the language as we know it, right? They, you know, we have pointers and references and the object model, and you just kind of do something very, very different, which is kind of a lot more based on Rust, right? So do you want to kind of just talk a little bit about how that works
Starting point is 00:13:48 and how that's different and why you do it this way? Sure. Consider lifetime safety, which is technology to prevent use after free bugs or dangling pointer bugs. We've had a solution for lifetime safety for lifetimes, right? And that's garbage collection. So in a garbage collected language, all your objects that support references go on the heap. And as long as there are outstanding or live references to those objects, those objects are in scope, they're initialized. So you can emulate that in C++ with shared pointers,
Starting point is 00:14:22 but it's no longer manual memory management, right? What Rust does is provides a technology for enforcing lifetime safety using manual memory management. So if you have an object that's not on the heap, but actually on the stack, and you want to pass references of that around to other functions, the borrow checker technology that Rust has will prevent other functions from using your data after it's gone out of scope. And it does this rigorously. There's no way to fool the borrow checker. But that reduces or restricts what you can express in the language. So you can't dereference raw pointers or legacy references in this safe context. You can't call other unsafe functions. You can't emit inline assembler. There's things that the compiler can't statically verify. So I thought that the language and the intensity of the warnings coming out of not just
Starting point is 00:15:17 the government, but Google and Microsoft, that's been so extreme that we need an extreme solution. The extreme solution is to just implement Rust's memory safety model in C++. So you get the rigorous memory safety that Rust provides, but you remain compatible with all your existing code. Your existing code, that does not make your existing code safe. If it has soundness bugs in it right now, it's going to keep having those until you harden it. But it allows you to at least get know get a running start so if you have
Starting point is 00:15:45 an existing c++ project you can start writing safe code and you can keep using your existing components right so let's talk a little bit more about how this works so instead of so obviously you know as soon as you have like just kind of pointers or references to go the old way like you can't really make that safe right people are saying i don't know for example rule pointers are obviously unsafe because you can do reference them and do whatever but like people are saying unique pointer is uh safe or safer um that's actually something i think i've pointed out in my own safety talk from uh cpnc last year that it's not really, right? Because yes, if you use it in a certain way, it's safe. But like, if you just, for example,
Starting point is 00:16:30 if you even want to just access the object inside, you need the star, sorry, not the star, the arrow operator, right? And what does the arrow operator return? It returns a reference, right? And so once you have that reference, you can like return it from somewhere, do whatever you want with it. Like dereference it later when the pointer is out of scope.
Starting point is 00:16:49 And that stuff just leaks out. And I just don't see any way you could possibly do this in C++ as long as you have pointers and references. So you kind of have to throw all that out and do something else. What does that look like? Yeah, you have to throw out legacy references and use check references, which are borrows. Same situation that Rust found itself. And if you import C++ code, or if you generate bindings to C++ code in Rust, those references come in as raw pointers because they're generally unsafe to dereference. You don't know if they're
Starting point is 00:17:23 pointing to uninitialized data, and you don't know if they're pointing to uninitialized data and you don't know if they're aliasing. One of the major restrictions in this model is no mutable aliasing. You can have mutable references to an object or you can have as many shared references as you want, but you can't have both at the same time because enforcing safety or guaranteeing safety
Starting point is 00:17:44 would then require whole program analysis, and that is not practical, especially for projects that are as large as C++ projects usually are. So how viral is this then? Because you said that you still got backwards compatibility, but how do you mix the safe and unsafe parts of what you've done? Right. So in Rust, all your functions are implicitly
Starting point is 00:18:07 unsafe in or unsafe they're i'm sorry in rust all your functions are safe by default uh in c++ they're unsafe by default so i have a safe specifier you put that on the end of the function declaration on the end of a function type like a like a no accept or something just like no accept so you might have like int main safe or void f no accept safe. So it's both no accept and it's safe. And that safe keyword now applies to the definition of the function. So in that safe function, you're not allowed to dereference pointers. You're not allowed to call other unsafe functions because that unsafe function may be dereferencing a pointer.
Starting point is 00:18:43 But that's not really the mechanism of safety. The safe specifier is more like a progress indicator. If you can compile your function and it's marked safe, that means that transitively, like you said, that viral aspect, that function and everything it calls is guaranteed to have no language undefined behavior. But that's not what actually eliminates undefined behavior. What eliminates undefined behavior
Starting point is 00:19:07 is reducing our exposure to unsafe APIs. So when it comes to taking existing code that is just like pointer spaghetti, the way to incrementally fix it is to replace unsafe primitives with safe primitives. Like you mentioned, unique pointer. Unique pointer is unsafe for a number of reasons. And I think that getting a reference out of it, which you can do anything with, is just one of those reasons, right? The more immediate one is
Starting point is 00:19:36 that, you know, unsafe has a default state, or I'm sorry, a unique pointer has a default state. So if you declare a unique pointer and use the default constructor, that's a null pointer. And now if we use star or arrow on it, we're going to get a null pointer to reference. And if we use arrow on a defaulted unique pointer, that's going to add some, may add some offset depending on
Starting point is 00:19:59 if it's trying to like funk down to a base class. And then we have like, we're dereferencing some small number and then you're already into kind of like thinking about exploits. So there's type safety concerns, there's lifetime safety concerns. And I think C++ is weak in all of these domains.
Starting point is 00:20:15 Most modern languages are really serious about type safety and then they diverge in the ways they address lifetime safety. You know, Python will use reference counting internally. Swift uses automatic reference counting. Java and C Sharp use garbage collection. And Rust uses static borrow checking.
Starting point is 00:20:33 So there's a whole assortment of solutions for lifetime safety. But all these modern languages are rigorous with respect to type safety, as in you can't use an object when it's in its wrong state. So using a unique pointer when it's got a null pointer inside it, that would be a type safety violation. So one of the challenges with C++ is that we have to make it safe
Starting point is 00:20:56 in all of these different categories, type safety, lifetime safety, down safety, spread safety. And that does require a lot of language changes and it's going to be an effort for teams that work on important network-facing libraries or applications to be able to harden their applications. Right, but I'm a bit confused here because I don't see how c++
Starting point is 00:21:25 could do this like let's say we have unique pointer and we wanted to make it safe but in c++ you know the idea of unique pointer unique pointer does two things right it has an object inside and like it's the only like pointer to that object? But the way this is implemented is with move semantics, right? So, you know, if you move, if UniquePointer supports move semantics, you have to be able to, like, move it, so you have to, like, then that leaves behind a move
Starting point is 00:21:56 from UniquePointer, and there is just no way to not have that. Like, it needs to have some kind of default state. Otherwise, you can't move out of it. And similarly, if you want to access the object inside, the only way to do this in C++ is with the error operator. And the only way you can implement that is by returning reference. So if you wouldn't have the error operator, you would never be able to call any member function on any object that's inside that
Starting point is 00:22:19 pointer. So how could that ever work differently? I'm very confused here. Well, you are an experienced podcast host setting me up beautifully. Right. So, okay, you got two, you named two different forms of lifetime safety. The first one is the null pointer. If we have a unique pointer and it might be null and it has to support a null state
Starting point is 00:22:39 to support move semantics, because if you move a unique pointer from the right-hand side to the left-hand side, you're zeroing out the right-hand side. Now, what you do is you have to create a new object model, one that supports relocation, right? So I have a keyword called rel, rel for relocate. And if I say auto y equal rel x, that will relocate the object x into the declaration y. And now the old x isn't like zeroed out.
Starting point is 00:23:15 It's just uninitialized and it's illegal at compile time to use it in any way other than to sign back into it. Wait, so if I, instead of, if I say a unique pointer and i say std move that somewhere else and then after that i have this like empty one left which i can do whatever with but if i say uh rel like unique pointer and then afterwards i try to
Starting point is 00:23:37 do anything with that it's just the compile error right um so it'll say that the object being named is uninitialized, or if you relocate it inside of control flow, it'll say it's potentially uninitialized. Or if you relocate some sub-object, it'll say it's partially uninitialized. You know, there's different ways. You have to come out with a complete object, right? So you're allowed to relocate sub-objects,
Starting point is 00:24:02 and you're allowed to relocate objects conditionally, but the data flow analysis will prevent you from using those. And that's done at compile time. So there's no cost to the user. And this lets us define a new unique pointer, like std2 unique pointer, which is
Starting point is 00:24:20 never null. So it doesn't have a default constructor, right? You're allowed to declare it without a constructor, and that declares an object that is uninitialized and then you can assign to it later when you're ready so it divorces formed it's it's like a compile error to do anything with it before you've initialized it right it's ill-formed to do anything with any of these objects before you've initialized them but how do you know like you can pass this object to another function which doesn't know if it's been initialized them. But how do you know? Like you can pass this object to another function which doesn't know if it's been initialized.
Starting point is 00:24:48 Any function parameters are initialized because transitability, like if a function calls another function and passes it arguments, those arguments have to be initialized or else it would be ill-formed to name them. So it's different from the concept in traditional C++ where initialized means, you know, you have assigned a value to it. It's a bit different, right?
Starting point is 00:25:09 Yeah. So in C++, all objects are initialized when they're declared, or at least local variables are. We can ignore statics and extern globals and things, but local variables are initialized when they're declared. If it's like a built-in type or a trivial class without a default constructor it might just be like trivial need trivially initialized which means it's still initialized but it's initialized to whatever stack garbage and it's kind of a poison value and you get into you know um initialization safety issues there but in in this new model you have to explicitly use like curly braces to initialize something or use some other explicit form. So yeah, the default constructor is no longer necessary.
Starting point is 00:25:49 And that means that I've also deleted the move constructor and move assignment because I'm saying there's no default state on this unique pointer. And therefore it's always safe to use star or always safe to use the arrow operator. All right, so instead of like just constructing it assigning to it and then moving it around you kind of initialize it and
Starting point is 00:26:11 then you like if to pass it around you kind of another function but borrows it or you like relocate it and then it's no longer there and then it goes into the other function that's interesting and how do you how do you then access the object inside if you don't have an error operator that returns a reference? Oh, you do have an error operator on unique pointer. Okay, but that returns a reference, right? So what prevents you from storing that reference and then doing whatever with that reference?
Starting point is 00:26:37 So it returns a borrow, right? Which is the checked reference. Rust has the borrow reference, which has got the ampersand syntax, but in C++, ampersand is already an L value reference. So I have a hat. The t hat would be a mutable borrow of t, and a const t hat is a shared borrow of t. Same semantics as Rust. And when you use star or arrow on the new unique pointer, it returns a borrow, and then the borrow checker goes in to prevent you from aliasing those or using them after the underlying data has been
Starting point is 00:27:11 freed. So if I use, or let's say, use unique pointer get, if I call unique pointer get and store out the borrow in another variable, and then I delete the unique pointer, and then I try to dereference the borrow, that's a compile-time borrow checker error because all accesses are checked, and it goes through all these live analysis passes, and it prevents undefined behaviors. It prevents use after free bugs. So the syntax for the borrowed reference is the hat or the little up arrow thing.
Starting point is 00:27:47 So there could be a potential clash there with the reflection proposal if we get that in the base C++. And with Objective-C as well. Sorry? With Objective-C as well. Because the reflection already clashes with Objective-C. Clang already said reflection can't use the hat operator for them because of Objective-C.
Starting point is 00:28:06 And now you also want to use that operator. I'll find a Unicode glyph that looks identical to hat and you'll just have to key it in every time. Right. Yeah, or just don't use Objective-C. Yeah. Right. So, like you mentioned,
Starting point is 00:28:24 I think what's interesting is you can you can interject this question about uh null pointer safety and unique pointer and then you can almost derive a whole bunch of memory safety almost the whole thing from that question so if we can't relocate or if we can't use stood move on um pointers or on unique, like we can't always relocate it either, right? You can only relocate objects that you own. Relocation requires compile time analysis. That means that you can only relocate functions that have flags indicating if they're initialized or if they're uninitialized. And you only get those flags for local objects in the function. So the question is, how do you move through a reference?
Starting point is 00:29:06 If you have a function and it returns a reference to an object, how do I move some sub-object out of there? And you can't do that with relocation directly. So then you have to use something like an option type, an optional type. In Rust, there's an idiom where you use their option etym and you specialize that over over some entity that can be a box like optional box a box is what they call unique pointer and then i can um relocate out of the option and that disengages the option so i've taken this payload out of this this optional and now the optional is empty uh and that requires like separating these two concerns, right? In C++, we've designed our core library types where they mix concerns that are really unrelated.
Starting point is 00:29:51 And I think that storing a null is a separate concern from storing a non-null. There should be two types, right? You should have a null pointer entry and a non-null pointer entry, and they should have different interfaces. And Rust, and not just Rust, like really all modern languages that allow null pointers, kind of separate them structurally.
Starting point is 00:30:12 So if you want to use unique pointers in a way where you can move them through arbitrary data structures, trees, and whatnot, put them in an option. And now to access the payload, we have to use pattern matching because std optional and std expected, which is new in C++23, those provide a star operator to access the payload. But if you're using the star on those
Starting point is 00:30:38 and the payload's disengaged because the optional is none or the expected holds the error, that's undefined behavior, right? So like there's two different core classes in C++, unique pointer or shared pointer and optional that both have UB warnings in the documentation for operator star, right? For different reasons.
Starting point is 00:30:59 One of them is this kind of null pointer safety. The other one is like variant safety or union safety because the optional holds two different states. So this new object model solves both those problems. You have to use pattern matching to access a choice type. And that also means there's a new choice type. This is
Starting point is 00:31:17 identical to the Rust enum. You write choice, and then you write your name of the object and curly braces and you indicate, these are the fields I want and these are the payloads, and then you write your your name of the object and curly braces and you indicate these are the fields i want and these are the payloads and then that type is compatible with relocation and pattern matching right and so you have replacement versions for like a lot of these facilities right you have stood to unique pointer and optional but also string and vector and presumably they're all written in terms of like borrows and you know kind of apis that don't let you yeah absolutely but they exist in the same they exist in the same type system as existing types so you can mix
Starting point is 00:31:57 legacy library types or your own types and these new types there it's not like um you're bridging between two different languages it's not like um you're bridging between two different languages it's not like i've like there's no interrupt question really you know they're all just types but these new types have additional guarantees with respect to safety but presumably if you have a safe function you can't like pass an unsafe object in as a parameter or something right uh you can't use it inside i mean if you if you have a safe function, you can pass pointers all you want, but you can't dereference them inside the safe function.
Starting point is 00:32:28 Yeah. So that means just don't mark your function safe until it's actually safe. Right. We want truth in advertising. And I think, you know, people are saying, well,
Starting point is 00:32:38 what if we drop some of these guarantees? What if we didn't? What if we don't introduce a variant, first class variant type so we can't write a first-class variant type so we can't write a safe optional? At that point, you can no longer guarantee safety, and then the whole safe specifier drops out
Starting point is 00:32:52 because you can never make these guarantees. So I see the benefit of not having to bridge between completely different languages, but I still think there is a bit of a barrier there, right? Because you can't just slap save onto existing functions like no existing c++ code will compile basically if you just put save on it right because you can't use references you can't use pointers you can't use any of the stl stuff uh presumably you also can't use any form of like you know random access like you do like with arrays or vectors you have have to do something like rust slicing.
Starting point is 00:33:27 Basically, all your algorithms, everything's just not going to compile anymore. So how do you... It sounds like I will still have to rewrite all of my code anyway because it is basically a new language, right? No, I think what you have to do is be judicious and draw boxes around things that need to be hardened. All of these safe components are written from unsafe code, right? There's a big book, the Rustnomicon, which is the art of writing unsafe code, and it details how to write like a vector class.
Starting point is 00:34:00 And the vector class has unsafe code in it and it can even use existing like unsafe components so in the demonstration i produced i have a thread class it's safe um and it's it wraps the stood thread class i have a mutex that's safe and it wraps the mutex i think what we have to think about doing is um learning how to wrap existing tested code if it's standard library code or if it's your own company's tested code, wrap that in a safe interface. And by doing that, I mean provide a new interface
Starting point is 00:34:33 that's of safe functions where it's impossible to raise undefined behavior. It's impossible to violate the contracts or the preconditions of those functions. So in Rust, you would use the unsafe keyword to opt out of the safety so you can do that. So do you have something similar then? Because so far we've only talked about the safe keyword.
Starting point is 00:34:53 Yeah, I got the unsafe keyword, sure. So in a safe function, I want to do a star around and do a pointer difference or whatever. Yeah, you put unsafe token there and it drops those guarantees. Okay, so when i first saw this i was kind of skeptical because i was like well if i have to rewrite all my code anyway i might as well do it in rust right because you know that is a language
Starting point is 00:35:17 that's already quite mature and then maybe we should just you know invest in better rust super sauce interrupt and like why is your stuff better than that? And don't we just end up with the worst Rust if we try to shoo her on the borrow checker into C++? But it seems like the benefit is this gradual... You can start out with a bubble of safe code or a wrapper of safe code around something that is unsafe unsafe but simple enough that you can reason about it and then that bubble can grow and kind of encompass more components of your program or something is that
Starting point is 00:35:54 kind of the the adoption model you're going for that makes it like a proposition but yeah but i think you're what's the idea yeah i think you're describing all of software engineering, which is just growing bubbles. It's just blowing bubbles as software, right? Yeah, I think we should take a breather because the standard line for years now was that it's impossible to make a memory-safe subset of C++, right? And then I demonstrate it. And then without two seconds of reflection,
Starting point is 00:36:26 everyone pivots to, oh, we should just invest more in Rust Interop, right? It's like you were just saying it's impossible to do this thing. And now what? Well, it's not a subset, right? It's like a superset of a subset. It's like you take a small subset
Starting point is 00:36:40 without pointers or references or any of the stuff that like 99 of the code uses everywhere and then you build new stuff on top of it so you kind of have to rewrite everything right you only have to rewrite it if you want the compiler to verify the soundness of your program i'd also nitpick team of your uh superset of a subset i'd say it's a subset of a superset. It sounds like Sean's introducing a number of language features that are useful independently of the memory safety side, like the choice type and pattern matching, for example. Right. I mean, I'm playing devil's advocate here.
Starting point is 00:37:20 Like, I love your stuff. I think it's really interesting. I just want to try and poke holes into it, right? Because i guess that's what everybody's going to do anyway as you say um but but yeah i mean i remember from your video you have quite a lot of stuff that you introduced kind of around it right you have like pattern matching you have like kind of language tuple types and all kinds of stuff and it kind of all builds on top of each other right yeah it's it's difficult to describe the solution in less than like uh two weeks so i could i could stand and like talk non-stop for a long time because um like c++ is very unsafe and it's easy to like to wave that away.
Starting point is 00:38:05 But I only discovered that while I was building this thing, like how like how many assumptions every line of C++ code makes. And to be able to bolt everything down and have something when people say it should be provably memory safe. I kind of object to that. I don't think it's about proofs, but it has something that is safe by construction or safe by design. That requires like a level of diligence that we haven't seen before. And on the other hand, I think that the compiler is doing all the hard work. I mean, the compiler is running these fairly sophisticated analysis passes so that you don't have to, right? It's impossible for a human being to do variance analysis in their head and then, you know, live analysis in their head and say, oh yeah, this code is good, right? We want to farm this work out to a computer and computers are good at doing logic and the computer will do it. We should trust the computer. So I think ultimately this is a labor-saving device,
Starting point is 00:39:06 the memory safety technology. Even though there are growing pains to be able to support high-value existing source bases to use these new safe features, in the end it's going to save us because we're moving the responsibility of verifying the soundness of our software away from the human programmer and to the computer. So how does this work in the compiler then? Do you have some kind of static analysis step in between the front end and the back end? Do you have redesign how the compiler works compared to what we do today in C++?
Starting point is 00:39:42 Yeah, so I basically did like a Dr. Frankenstein operation. So I cut the compiler's head off the front end and then it's got a new body. Like normally you ingest text files and you tokenize them and then you lower those tokens to abstract syntax tree and you lower that abstract syntax tree to like LLVM and that lowers LL llvm ir to assembly now there's a huge like a big new box now which is mid-level ir so after you've um parsed the program and you have ast you have to lower that to mid-level ir which is a control flow graph um that yeah a control flow
Starting point is 00:40:18 graph is a graph of basic blocks and basic blocks is a sequence of instructions that don't have any branching and then the terminators in a basic block are edges or branches to other basic blocks and you can represent the control flow of the program with a control flow graph the mid-level ir is a flavor of a control flow graph that has a bunch of metadata information for um supporting both the relocation semantics and the borrow checker semantics. So we need to be able to determine which objects or which sub-objects are initialized or uninitialized at any point and raise an error if they're used. And we need to be able to confirm that we're not aliasing mutable borrows. And we have to confirm that any dereference of a borrow
Starting point is 00:41:07 is to a place that is still initialized. This requires a lot of new engineering because I basically have a new backend, a new middle end. So yeah, everyone's going to have to like saw their compiler in half. But the upside is that we have this capability that the government and other corporations are saying c++ can't go forward without you know if the
Starting point is 00:41:32 if the the choice is between surgery and the extinction of of the language i think we have to do surgeries i i feel like our hands are being forced on this so so i have a couple more questions so you're talking about memory safety um but there's lots of other sources of ub and it's a language that doesn't necessarily have to do with like pointers or references right arithmetic overflow is ub like an infinite loop that you know doesn't write anything anywhere is UBE. There's probably like three dozen other sources of UBE that actually doesn't have to do with accessing objects. Sure. These are tackled individually.
Starting point is 00:42:16 Right now in my model, signed integer overflow is defined as wraparound, which is what you get coming out of the hardware anyways. The poison on signed overflow is an optimization to allow you to kind of factor out common terms on both left and right-hand side of comparisons and things. There's good reasons for it to exist, but it's really easy to have integer wraparound and you have very hard to understand bugs later on.
Starting point is 00:42:41 So that is fixed. Bounce checking, there are new types to do, like slice type, which I've got from Rust, to do runtime bounce checking. So if there's an out-of-bounds subscript on an array or a slice, that raises a runtime panic. So it prints out the line number where the index occurred, and it will abort the program. Aborting the program is preferable to it continuing to run after some undefined behavior, because that is a major source of security vulnerabilities. Things like loops that don't break, that don't exit and don't have any side effects. That's something that just has to be
Starting point is 00:43:25 fixed in the code generator i think rust just fixed it like last year it took a long time for lvm to put patches in that so these these are things you just you know you make a list and you took them off but they're all kind of local local concerns the real non-local concern in this is is the lifetime safety um so i think those ones they're easy and they're low hanging fruit and we should have done that with c++ already like the i the fact that ones they're easy and they're low hanging fruit and we should have done that with c++ already like the i the fact that we're in 2024 and we're still arguing about um signed ninja rover flow is crazy i mean that's so easy to so easy to address in so many different ways so what about uh runtime overhead some of those things you mentioned like balance checking
Starting point is 00:44:00 suggests there's going to be some runtime overhead there is runtime overhead when you do balance checking on random access uh fortunately most data access is like sequential so you're going to loop over some arrays and there are you i mean in existing code you're already doing comparisons pointer comparisons or uh index. So, you know, you can, my tool, you can instrument it and you can time, you know, with and without the runtime, the runtime check. And I think it's just good to be able to turn those things off easily, both with command line switches and at the file level and at the individual instruction level. I have like an unchecked keyword right now.
Starting point is 00:44:44 I don't know if that's going to stay in much longer, but that will turn off any runtime checks. So you can say unchecked, and then you can put some expression, and it continues to support lifetime safety, type safety, et cetera, but it turns off the expensive calculations. So if you're inside of code and you understand the preconditions and you've taken responsibility for subscripting, then fine, turn that off and don't pay the tax.
Starting point is 00:45:07 But I think we need to have the option there. Most of these random accesses are not in the hot loops of programs. Very, very similar to what Tristan Brindle was saying. We had him on a while ago to talk about his sequences library, which is balance-checked,
Starting point is 00:45:24 but he found that most of the balance checks were optimized away because they're just repeating what the compiler can already see has been done yeah the flux library yeah that's the one yeah yeah yeah i know he um he does a good job at addressing the defects both the safety defects and the usability defects in the um c++ iterator model where you have begin and begin and end iterators they're like really easy to invalidate when you you know if you do a pushback on a vector inside a range loop then like that invalidates your loop and it leaves you in an undefined state and his his uh the flux package fixes that and it also has some advantages over
Starting point is 00:46:02 rust with respect to expressiveness so i think that's like a really good direction to pursue that kind of iterated design he has so there's actually one other safety that we haven't talked about which i think is the hardest of all of them that's threat safety and how to prevent data races because with like even with uh like memory safety today in c++ you know we have we can like have a sanitizer that can track all the allocations or whatever. But with threat safety, it's non-deterministic, right? And you can't possibly check every possible threat until leaving. So there's not really anything today we can do about race conditions
Starting point is 00:46:43 and preventing them in C++, apart from writing code that just doesn't have them, which is extremely hard. So how do you tackle that problem? Right. The problem of data races. Rust has a two-pronged approach. The first part of this is to use these send and sync marker trades to advertise which types can be referenced across threads and which types can be copied across threads. Most of these traits are implemented automatically just by examining the sub-objects of your types. But if you create a new type that is supposed to be thread safe, like a mutex, you have to mark it as being send depending on what its inner type is.
Starting point is 00:47:29 So part of this, the Rust solution is expressing the thread safety of types through the type system. And once you're within a worker thread, the borrow checker comes in and prevents you from accessing shared mutable state from outside of a lock. I think kind of the highlight of my YouTube demo that I gave to the committee is kind of a battery of thread safety demonstrations where I try to raise a data race.
Starting point is 00:48:01 I try to mutate a shared state outside of a lock and the type system or the borrow checker will prevent you in all of these cases in safe code, right? So when it comes to using it, what you do is you make a shared pointer of a mutex of T, where T is whatever your shared mutable state is. It can be a structure of a bunch of things. And now you can copy that shared pointer to your worker threads. And inside that worker thread, you can form a lock on the mutex. And then on that lock, you can get a borrow. And then you can access the data mutably through that borrow. And the borrow checker prevents the use of that data after the lock has ended, right? So you've created this network of constraints.
Starting point is 00:48:52 One of the constraints is that the reference to your data has to be outlived by the lock, and the lock has to be outlived by the mutex. So, you know know you run these things through this compile time constraint solver it's like kind of a wild iterative solver grows these regions um and if any of these constraints are violated you get a compile time error so it actually tells you at compile time if you have a potential data race in your program, which is like really a lot better than running sanitizers that may only hit at scale and you probably aren't running your sanitizer at scale.
Starting point is 00:49:33 So it gives you a lot more security and confidence about the integrity of your multi-threaded program, this system. So this all works in C++ fine. People were afraid about it feeling bolted on, but I don't think it feels bolted on. this system. So this all works in C++ fine. People were afraid about it feeling bolted on, but I don't think it feels bolted on. We still have operator overloading. We still have
Starting point is 00:49:52 all the features people complain about, like argument-dependent lookup and templates being impenetrable. It is C++ still, but it's C++ that has safety features that are, I think, really fairly seamlessly integrated with the rest of the language.
Starting point is 00:50:09 Right. So since you talk about C++, and you mentioned the committee there somewhere, and I think you mentioned earlier that everybody will have to solve their compiler in half and put something in there. So presumably, in order to get there there we need to actually somehow put this into C++ right now it lives in Circle which is your proprietary kind of compiler
Starting point is 00:50:32 for your version of the language but in order to put it into actual C++ you know you would have to like basically standardize all this and put this through the ISO standard committee process which relocation alone I think we have been discussing for at least six years and haven't gotten particularly far.
Starting point is 00:50:51 And on top of that, you have the whole like borrows, you have these like lifetime parameters that you kind of add. You have all of these other features. You introduce language tuples, language variants, your own pattern matching syntax. You have tail expressions, I think, in there and slices and interfaces, which seems to be something similar to Rust traits
Starting point is 00:51:15 and send and sync. And like, I could go on all day. Like, it would take at least a decade, I think, to get like maybe two decades to get this through the ISOC or SAS committee and into language. So it doesn't seem really like a viable route. Like, what should we
Starting point is 00:51:31 do then? How do we actually get this out and allow people to use this for production? Right. I think there are trillions of dollars of value tied up in C++ source spaces, right? There has to be a way to keep that value going forward into the future. And if we end up being
Starting point is 00:51:57 regulated out of existence, because if your office or your Google AI or whatever is deemed to be too unsafe in C++, we're going to have a real problem. So I think there's huge commercial pressure. And I think that one of the big vendors, like a Microsoft or a Google or someone else with literally trillions of dollars of value at play here, they built their companies on C++. They should build an industrial-strength, safe C++, they should build an industrial strength safe C++ toolchain. However that it wants to be chewed up through the committee, you're going to have to find something that goes
Starting point is 00:52:33 through, but I think just do a big technical specification of, I don't know, 300 pages. Otherwise, you're right. We can't get relocation through. We can't get pattern matching through. We can't get choice types through. They've been tried before. And you think it'd be a lot harder with this whole vision because it's hard to implement. It's hard to
Starting point is 00:52:56 specify. Rust isn't even specified. There's no Rust specification. I think we need leadership and we need a big company to step forward and say, oh, this is important for our company, not just for the standard committee, to have a viable path to memory safety that we can move our existing applications to. The rewrite and rust thing is never going to fly. C++ people are not going to learn Rust. It's hard to learn a second language when you're a grown person. You don't have the child's brain, the elasticity anymore.
Starting point is 00:53:27 Yeah, I think it has to be done. I don't have an answer about the committee. I think we need other language experts to take this seriously and actually like do their homework and research and understand the problem though. You know, how does borrow checking work? Not many C++ people know that, like very, very few. And it's really critical that this become more common knowledge. So I think people involved in standardization should really go do their homework. They should read the non-lexical lifetime RFC that is the best description of the Rust borrow checker technology. And also read the Rustnomicon, which explains more generally the memory safety strategy
Starting point is 00:54:12 and how to write unsafe code that satisfies the preconditions of the functions. You know, and then kind of start keeping in their head when they write their own C++, like, well, what am I taking for granted here? What could possibly go wrong that would raise undefined behavior? I don't know. The answer is I don't know, but I think something has to be done here. And one of the big vendors, which has the, they have the resources to push this thing through. They should just build a tool chain. But it's all implemented in circle today and circle is not just like a
Starting point is 00:54:48 pet side project for you it's meant to be an industrial strength it's an obsession with me yeah it's definitely an obsession no i think i think you don't want people to use it so yeah um it's hard being a one-person shop with no funding or no help or anything. Um, but yeah, I think, I think just like adopting what I have would be, would be really smart. Um, because, you know, I don't mind, I do mind, but I'm the kind of weirdo who will just go and like, say, I'm going to create a new back half of the compiler. You know, it has to be done. So you just like sit down and you start writing it and it's
Starting point is 00:55:25 it's hard to get that level of brashness from a company you know i i don't know if microsoft is going to say well today's the day we're going to like just rewrite visual c++ so you know well i think they have like 100 million lines of code or something there so like even if they wanted to i don't think you can just do that. It would take like, I don't know, a million years to do that or something because the legacy code bases are so big. Well, someone wrote it in the first place, so there are people to rewrite it.
Starting point is 00:55:56 I think we're too dismissive about the ability for people to rewrite stuff. The Chromium project is the one effort that has taken memory safety really seriously. They went through and replaced all the pointers in Chromium with Miracle Pointer, which is kind of a type-safe class. It's kind of like a shared pointer. It has a control block,
Starting point is 00:56:16 and it will point out use after free. That's an incredible operation. And they've been doing the same thing with bounce checking now. So they're going through and all the array or vector dereferences, they're replacing with a thing called, I think, base span,
Starting point is 00:56:29 which does bounce checking. And they've got some small playing extensions to kind of warn when they're not using it. But it's a lot of, I mean, there's a lot of touches. They're touching the code like millions of places, but it can be done. And this team is doing it and it's on a timeline of months for these operations. And then it'll be used for
Starting point is 00:56:50 another couple decades. These are long-running programs. So if you consider the amount of effort required to harden things, and then you divide that by the number of years we expect these programs to be used in the future, it becomes like not a bad cost benefit ratio. So, okay. I guess I'm being like the critical one here, but something that I noticed is that, you know, as we discussed, a lot of noise has been made around this whole safety thing
Starting point is 00:57:24 and governments are pushing for it. And, but at the same time, like, for example, we discussed the, what was it? The developer survey, the standard foundation developer survey that came out like a month ago or something where they had, you know, what's the biggest pain point in C++ for you and memory safety, which was like, or like the first thing that
Starting point is 00:57:47 had anything to do with safety or ub which i think was memory safety was like number nine it was like really far down the list and and then there are so so like it seems like day-to-day developers don't really care about the stuff and there's whole industries like video games where like you just want it to be fast like you don't care like okay the game like there's a industries like video games where like you just want it to be fast like you don't care like okay the game like there's a glitch or whatever like all the stuff that's the sensitive or you care about not being hacked that's like i don't know something that touches the user data or talks to the server that's like not written in c++ in the first place that's like like a particular part of your game that's like you know kind of compartmentalized in a particular way but
Starting point is 00:58:25 then the like all the all the graphics and everything like you don't really care if it has ub right just needs to be fast and look awesome uh so i love it people in all these industries they'll always point to video games as the reason not to care about memory safety they're working in banking or something like this ps5 games sometimes crashes like here's the thing that's not your industry unless you're actually working on car racing video games it's like you shouldn't be using that as excuse you know no i mean obviously people obviously people exploit and it's a huge thing but my point was that it's a huge thing for certain industries or certain the code that runs on the internet touches the internet things like
Starting point is 00:59:06 that right but not like i don't know the code that runs on my toaster sure or like i'm not right so so it's not that you know everybody has to do it this way now it's like i just kind of don't buy that no i'm not i'm not saying that either. I'm not the nanny state. I don't care how people write their software. But I think it's critical that we provide tooling that achieves memory safety. If C++ goes on as a terribly memory unsafe language, it's not going to be used in any domain at some point
Starting point is 00:59:41 because the support is going to dry up, right? Professors aren't going to be used in any domain at some point because the the support is going to dry up right professors aren't going to teach it and then the pipeline shrinks down and then you can't hire engineers to work on your software and it becomes like cobalt or fortran and that's really bad because cobalt and fortran did not have like you know massive trillion dollar market values right c++ does because c++ is the first really mega language of the industrial age here. Or I could say C is too, but C's got obviously the same problems. Yeah, we have to find a solution. I'm not saying everyone has to care about memory safety, but C++ needs an evolution strategy here. And the one I'm presenting is the only strategy for memory safety, right? Not my
Starting point is 01:00:26 implementation. I'm saying that the features I've noted, right, the relocation semantics, the borrow checking, any other serious effort to make C++ memory safe are going to have to do the same thing. They're going to look very similar to this, right? There's no other design space. Like this is the design space for making a memory safe language that supports manual memory management and i think it's also true that you know some some projects are going to be more sensitive to safety and security issues than others but i'd say particularly like low-level libraries cryptography networking that sort of thing that's obviously going to be critical and being able to integrate that into your existing c++ projects would be a big win i think having kind of very
Starting point is 01:01:13 versions of those yeah i think the same point from a different angle is that if you're making a library and it be i don't database some kind of database or something you're going to going forward you're going to want to write that in a memory-safe language because you want to make it available to projects that demand memory safety. And you're going to get more play if you do something that will deploy into every domain. Continuing to write unsafe libraries, it's just limiting your audience. So I think C++ will have the maximum reach and it will still be applicable language for all kinds of applications if it has opt-in
Starting point is 01:01:51 memory safety. I'm not coercing, I'm not twisting arms saying anyone has to write memory safe code. I mean, I'm not writing memory safe code, clearly. I'm writing C++ compiler in C++, but the option has to be there so we can grow a new ecosystem and still be competitive. I know a lot of people involved in Conference Circle and the standardization meetings are already saying we should just cede this territory to Rust. If people are in a domain where they need memory safety, just cede it to Rust. It's like you haven't even fought the battle and are already surrendering, right? These things are fought over decades because the amount of code out there, and we have a good opportunity here.
Starting point is 01:02:33 Most of the C++ language is fine, or, well, at least it's not more defective than we already know about, right? Like most of the front-end stuff, the overloading, the way the declarations go, all the ABI stuff, you can keep rolling with that. We've just got to add memory safety. It's not the end of the front end stuff, the overloading, the way the declarations go, all the ABI stuff, you can keep rolling with that. We just got to add memory safety. It's not the end of the world. It certainly doesn't merit like just jumping ship
Starting point is 01:02:52 and saying, well, we're just not going to compete. Well, again, to be devil's advocate, just last episode, we had Mara Boss on the show and she's the team lead for the Rust Standard Library. And we talked about that quite a lot. And she was saying, she came from like C++ and founded a company that's doing embedded drone stuff which is kind of one of the places where you would normally definitely use c and c++ and she said like once they switch to rust like it's not just memory safety it's like so much easier to teach you know
Starting point is 01:03:21 it's so much easier to just the ergonomics of and the whole ecosystem like how easy it is to pull in a third-party library and because you have cargo like it's not just the memory safety it's it's all of the other stuff so it feels to me that if i have to do stuff with c++ then so if if i don't have these like memory constraints and i would write c++ because that's what i know if i if i do have these constraints um and i would like start a new project like i wouldn't even touch c++ i would just go straight for us i just don't see a reason to like use this unless i have to support legacy c++ code as part of it right uh yeah but that's everyone getting paid right now is getting paid to work on legacy C++ projects. Who's doing
Starting point is 01:04:08 Greenfield projects really? Also, I don't think C++ would be worse for Greenfield projects. There's parts about C++ I really prefer over Rust. You're right, cargo is nice, but again, cargo may not be what everyone wants. C++ is just
Starting point is 01:04:27 a different strategy. Strategy is something for everyone or customizability. There's so many different build systems and competing package managers. I mean, we all complain about them. But for big companies that have really weird needs, that's important to have that flexibility. And I don't think the one-size-fits- all that rust is predicated on is serving their needs at least that's from what i hear you know these big companies they're not they're not just switching to rust right they're talking about doing it but you know there's there's so many barriers and i think the safe c++ is the way to start integrating memory safety with without you know without considering these barriers like you don't have to change your build system cargo is great but if you're already using ninja and
Starting point is 01:05:11 cmake or or basil or whatever you keep using that right oh yeah yeah keep doing what you're doing i wouldn't like rewrite stuff and throw all of that out i'm just for a greenfield project probably i would now with all the information I have, like, think twice before, like, starting it in C++. I think we can improve C++ in many dimensions and make it competitive with Rust, even as far as convenience to getting new projects started
Starting point is 01:05:36 with package management and things like that. Well, that is something I would really like to see. Because I love C++. C++ is great, but it is complex, it's hard to great, but it is complex. It's hard to teach and it has all of these infrastructure problems. Rust is hard and complex.
Starting point is 01:05:49 Yeah, I think you can say the same thing about Rust. It's just, it's a new thing. And I think the Rust users are early adopters and they're passionate and they're smarter than like average C++ people just because they're self-selected. They're the language fanatics. They love programming languages.
Starting point is 01:06:03 And so, yeah, it's got a lot of momentum right now. People like Mara,a very sharp very creative yeah it has a lot of momentum but c++ can have momentum too it's we can change the language and have it suit our needs well we could talk about this for hours i'm sure but we do have to and i'm sorry to say this come full circle it's a new one it's new one for me classic phil thank you classic phil yeah just just before we we wrap up just to bring back to circle itself i mean what what is your long-term plan with with circle do you do plan to continue in this direction yeah i'm i'm a big moby dick fan as everyone knows and i really identify with ahab's quest uh so this may lead me to oblivion but you know that's what i signed up for i guess I'm a big Moby Dick fan, as everyone knows, and I really identify with Ahab's quest.
Starting point is 01:06:47 So this may lead me to oblivion, but that's what I signed up for, I guess. So yeah, my obsession is to deliver a safe C++ toolchain. And our final question is, we're really at risk of opening another can of worms, but is there anything else in the world of C++ or around it that you do find particularly interesting or exciting i don't know i got blinders right now everything i see is about
Starting point is 01:07:10 undefined behaviors so that's just all i'm thinking about right now i can't i can't consider other things all right so what's your favorite undefined behavior um i guess the use after free because um it's like you discover quantum mechanics when you try to solve it. It's just, it leads to technology that is so alien and creative. I think the borrow checkers, like it's amazing. It's amazing technology.
Starting point is 01:07:35 And I, I hope that we can start talking about it. I mean, with the committee or with other compiler developers in detail, because it's a, it's a fascinating work of, of, of engineering so i i think use after free is great because the solution is so great interesting that that's a great answer
Starting point is 01:07:53 thank you i like that all right well we do have to to wrap it up here so anything else you want to tell us like where people can find you or find out more about Circle? Yeah, I have a Twitter, if you're still on the Twitter, now known as something else. It's SeanBax, S-E-A-N-B-A-X. You can email me at seanbax.circle at gmail. That's probably the best way to get a hold of me. Yeah, if you want to talk memory safety,
Starting point is 01:08:18 look me up. We'll put those in the show notes. Thank you very much for coming on, telling us about Circle and how you've managed to implement a borrow check in C++. That's fascinating. Yeah, thanks for coming on the show. Thank you. Thanks so much for listening in as we chat about C++.
Starting point is 01:08:35 We'd love to hear what you think of the podcast. Please let us know if we're discussing the stuff you're interested in, or if you have a suggestion for a guest or topic, we'd love to hear about that too. You can email all your thoughts to feedback at cppcast.com. We'd also appreciate it if you can follow CppCast on Twitter or Mastodon. You can also follow me and Phil individually on Twitter or Mastodon. All those links, as well as the show notes, can be found on the podcast website at cppcast.com. The theme music for this episode was provided by podcastthemes.com.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.