CppCast - Safe, Borrow-Checked, C++
Episode Date: May 31, 2024Sean 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)
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?
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
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.
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
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
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.
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
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
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
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
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
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
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
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,
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
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
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++.
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
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
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.
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
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.
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.
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,
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.
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
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.
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
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
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,
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
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
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,
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.
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
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
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
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.
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
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
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
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.
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.
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
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++
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
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
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
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.
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
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,
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
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.
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?
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.
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
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?
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
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.
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.
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,
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?
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.
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.
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
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.
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
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
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.
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,
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
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.
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.
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
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.
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
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
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,
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
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.
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.
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,
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++?
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
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
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
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.
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.
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
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
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.
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.
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,
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
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
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.
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.
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.
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.
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
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.
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
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.
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
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
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
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
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
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.
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
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
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
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.
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,
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,
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
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
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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.
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.
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.
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
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.
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
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,
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++.
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.