C++ Club - Embedded C++, Cpp2, September mailing
Episode Date: October 10, 2022With Gianluca Delfino and other colleagues.Video: https://youtu.be/67bDhqV2nzkNotes: https://cppclub.uk/meetings/2022/154/...
Transcript
Discussion (0)
Okay, welcome to C++ Club. This is Meeting 154 and today is the 30th of September 2022.
We'll start with a CppCon keynote by Bjarne. The topic this time was C++ in constrained environments. And I thought I'd quickly summarize the talk.
The embedded and other constrained environments have been not covered enough in the mainstream
C++. Well, I guess there were quite a few presentations, but if people don't work in that area,
they might not be aware of the constraints that the embedded developers face.
So I guess Bjarne decided to address that and all the other problems that stem from the constraints.
He said that many systems have constraints that dominate the design, like limited memory,
limited CPU speed, extreme reliability requirements, limited latency, zero or limited downtime,
and long life, like decades long.
But when teaching C++ these constraints are usually ignored. The focus on constrained environments is at reliability,
because a space probe is not easy to repair. Dependability, a car on a bank or a bank or
piece of medical hardware where failure can be disastrous. Resource constraints, small relative to the task they handle, a search
protector or a smartwatch, and messy problems like hardware problems and unusual attached devices,
and also maintainability, which is the lifetime of those devices, can be measured in decades. He said that there is no silver bullet.
We need to use several approaches in larger systems adapted for those systems. You can target
C++20, but in many cases your code has to be usable starting from C++11. And some people are unfortunately stuck with C++98.
And Bjarne said about it that that really shouldn't happen these days. We know it does happen,
unfortunately. He had a slide on common misconceptions and the bullets where learning C is a prerequisite for learning C++, which is not true for modern C++, like K. Gregory said many
times. It's useful to know, I mean, the concept of pointers is definitely useful
to know, but it's not what modern C++ teaching should probably start with.
Another bullet point was C is the best C++ subset for constrained systems, which is not true
anymore. You can use more features of C++ than just C-like code.
Another one was, good C++ relies on a lot of dynamic memory use
and large class hierarchies with runtime resolution
of all function calls.
That hasn't been true for a long time.
Of course, as they say, you can write Java
in any programming language.
And much of the code I see
every day uses shared pointers everywhere. But the guideline I saw was
that you should keep your hierarchies shallow in C++. I remember when I started
working with.NET and C-sharp, the class hierarchies there were like 30 level deep,
especially in WPF, if anyone remembers various controls and all the hierarchies.
That's not the C++ way.
Another misconception. To be reliable, code must be littered with runtime tests.
He says that's not true and you should always prefer compile time tests as much as possible
and compile time verification, static analysis and such.
And the last point is probably the most contentious lately, was embedded systems must avoid exceptions.
To which Bjarne said it's true only for some tiny systems and some hard real-time systems.
He said that language serves the programmer, not the other way around, so you should use
as many new features as it is sensible for your environment.
Of course, your compiler that you're using for a particular embedded system might not support
the latest C++ features, but you should strive for using more of those as much as it makes sense for
you. Regarding optimization, he said don't optimize every line of code. Measure, then tune.
C and C++ map directly to hardware, thanks to the genius of Denis Richie.
And C++ machine is itself an abstraction. You should make your every construct checkable,
so that rules are expressed in the code. Static checking can be
difficult or impossible and runtime checking can be expensive. You should try using immutable data
as much as possible which protects against data races. You should definitely initialize your data. C++ strives for zero overhead.
You should leave no room below C++.
But that doesn't mean zero cost.
You pay for what you use.
For resource management, use ArrayAI.
You should move work from runtime to compile time, if you can.
And with modern C++++ you can avoid falling back
to C-style C++ and unsafe practices. If you attempt to create a safe subset of C++, like
many embedded shops do, I guess, or especially game programmers like to do, in that case you end up
having to write more code that has to be correct
because you can't use all the available language facilities. To avoid using unsafe techniques you
can extend the language using STL and GSL guidelines support library from Microsoft
and you should not aim to be stuck with classic non-modern C++. If you remember
we discussed at some point GitHub repository which is called... I forget
traditional C++ or no it was like something like... it was dedicated to guidelines
for writing C-like, C++, C with classes, style, C++.
And I think the creator of that was a game developer.
Of course, don't do that.
Now, the next series of slides was about error handling, and I especially liked this illustration,
which is really creepy and scary.
Quote, don't even dream of a single style of error handling for everyone supported
by a single language construct. End quote. So you can use exceptions and you can use return
codes, whatever makes sense for you. But sometimes you don't have an alternative,
like you would only use exceptions to report errors in constructors,
operators and callbacks. Of course there's like two-stage initialization
that some people use where if the constructor fails and they can't throw
they set a flag. That's suboptimal. You end up with a half-constructed object.
Return codes use them only in hard real-time code, where there are latency guarantees.
If you can use crash terminate, then that's, I guess, universal. But not everyone can use it.
I mean, if your game or a GUI program or an automotive display suddenly crashes and restarts,
that's not ideal. Actually, I remember someone was presenting a talk about a Mars rover,
and they said that if anything bad happens, the default, I think, is to just terminate and restart the entire system.
Just to be sure.
Regarding exceptions, Bjarne said,
Exceptions are not zero overhead, but neither are other error handling strategies.
They can be zero overhead on the happy path. That's what exceptions
are. I think on 64 bit ABI, they are pretty much zero overhead on the happy path.
Yes, it's really almost impossible to measure on most compilers the effect of exceptions
on the happy path. And obviously, when people want to demonstrate
that there is a cost to exception,
they put exceptions in logic
that drives some sort of error handling code.
And obviously then, you know,
you can measure the stuck unwinding.
Yes.
On the other hand,
use exception handling sensibly.
Don't litter your code with try-catch. That kind of defies the
purpose. Handle exceptions at the point where handling them makes sense. And don't use exceptions
for common failures that can be handled locally and are expected, I guess. I have the next slide, which is return an error indicator,
an error code, when a failure is normal and expected,
or an immediate caller can reasonably
be expected to handle the failure,
or a system has so little memory that the runtime support
for exceptions would crowd out in central functionality.
Or the code is already a mass of pointers with no implicit resource release.
Or an error happens in one of a set of parallel tasks and we need to know which task failed.
Don't even try to percolate every error to a handler.
It's expensive, it simulates exception handling and is extremely hard to get completely right.
That was it for the error handling part.
Bjarne followed with his dreams of the future. Regarding the ISO standard he
hopes for executors, a more comprehensive model of concurrency, pattern matching,
simple uniform type safe and efficient model of selection, static reflection, yes
a simple way of generating code based on already defined code.
Better library support for coroutines.
Make the preprocessor redundant.
I think we're getting there.
And integrated language support for static analysis, like safety guarantees.
Stability and compatibility is a crucial feature.
And performance. No bloat in the implementation of language features and standard library components.
He continued with this.
Not all needed major new facilities are language and library facilities.
For that, we need a package mechanism and a repository of packages.
These are common pain points.
Whenever anyone asks on Reddit,
what are your pain points in C++?
Almost the first answer is always package management.
He also said static analyzers
with support for profiles of specified language guarantees,
like guarantee type safety.
Static analysis supporting code transformation,
like upgrading to use newer features and techniques.
Hmm.
That definitely reminds me of Carbon Goals.
And also, if you remember, Google has a library called AppSale, which they aimed for
people to use at master, at the latest tip of the code. And they promised to provide a software tool
that would allow people to migrate to the latest code if need be.
So that definitely rings a bell here. Of course that's never gonna be
standardized but still we need it. And more C++ core guidelines, for example in
the concurrency area. We need more people to adopt the ones that are there already.
We need advertisements for the core guidelines ones that are there already. We need advertisements
for the core guidelines.
They're not as well known as they should
be. That is very
true. Client ID
has a set of checks for
the guidelines, I think.
And now the modern
Visual Studio versions, I think
starting with 17 even,
had a guidelines checker.
Visual Studio has always been up there, you know, because Herb Sutter is always there pushing for
them. And they got there going for it. A good presentation as usual. And I just pre-ordered
my copy of the Tour of C++, the new edition, the third edition aimed for C++20. And maybe if Bjarne visits London at some point, I'll get it signed.
Right, on to the next big topic today.
Herb Sutter's keynote.
Can C++ be 10 times simpler and safer?
That's a big one.
Basically, this is Herb Sutter's personal C++ evolution experiment.
These are...
None of the many.
Indeed.
These seem to be popular lately.
This one has some distinct goals compared with others.
He says the goal is to refresh C++ itself, not invent a new language.
His main idea is apply zero overhead principle to backward compatibility.
Pay only if you use it. Second syntax for C++.
He said if it doesn't hurt a little is it really C++? And then proceeded to
try to remove the pain points. Basically he implemented his own major papers.
Metaclasses... well, that's coming.
It's not implemented yet, but I think his goal is to implement
metaclasses in Cpp2. Value exceptions also not ready. Parameter passing is
there and isAsPatternMatching is partially there. He started implementing it.
Well, I guess that's one way of getting your paper into C++.
What if he doesn't get his paper eventually into C++?
Is he going to fork as well?
He's already on the way.
He still claims he wants this to be a continuation of C++,
but effectively
is diverging already i don't know he can always keep this as a running experiment i mean he doesn't
make any promises so i guess people be using it people will be using it even if it doesn't
get standardized or anything
listen i think he certainly hopes that he's gonna take off you know i keep saying in the presentation now this is an experiment he's going to fail or whatever he's he's playing it very cautiously but
yes it's pretty obvious that he wants this to succeed uh as you know normally people would
and you know at this point you know what if it doesn't get this thing to actually
eventually get merged back into the standard one way or another, which I don't think it's
going to actually be. I don't know. We already got Aleksandr Skud trying to defect and going into D.
Exactly. All good questions and there's no way to tell. So far it looks like he wants to keep
on using C++ in whichever form, so that's probably a good sign. But yeah,
anything can happen if he doesn't get his way. I mean, the presentations about his meta classes and value exceptions were quite a while ago,
and the papers are not progressing in any meaningful way.
So I guess he's trying something else now.
To me, it distinctly feels like TypeScript versus JavaScript.
I think that's an apt comparison.
TypeScript was definitely an improvement
over JavaScript.
Everybody loved it.
I think that's what
you would like to see as a response.
To an extent,
it makes sense that people try.
Yeah.
And people still use both
JavaScript and TypeScript.
Yeah, but you know, at least you can see it, you know, you can say, okay, TypeScript
is probably better, you know, in many aspects.
You're still gonna have JavaScript laying around.
You just introduced a new dialect in a way, which is a problem.
But maybe you did move into the right direction
and then maybe you could envision people moving there. Here I'm not sure. Also, I don't know
if this actually solves the problems that it's trying to accomplish with this. So I
don't know. Yeah.
JavaScript ended up like sort of an assembler, a runtime for some uses like Wasm, for example,
Web Assembly, right?
It compiles to JavaScript, as far as I know, right?
Or is there...
There is a native component to it, I think, but by default I think it compiles to JavaScript.
So what if we end up with C++ being sort of an assembler language that no one uses directly?
In one layer down.
It's like an intermediate representation before the intermediate representation.
Something like another level of interaction,
which apparently solves all problems except one.
I don't know.
I know there's a language called Yacht,
which was created by the author of Serenity OS,
which was written from scratch in C++.
But Yacht is their goal for the official main language for Serenity OS. And at the moment I think it compiles to C++, or it used to compile to C++ in the beginning.
So yeah, C++ is already kind of an intermediate language.
And lots of code generation tools also generate C++.
And now we have one more of those.
At least this one hopes to generate good looking and readable C++, which, you know,
that's going for it.
Yes, that definitely is a good thing.
So Herb said, what would Bjarne do?
And he meant 40 years ago.
40 years ago, Bjarne wrote Cfront,
which translated C++ code to C.
And so Herb Sutter now wrote CppFront,
which translates C++ or Cpp2, like he calls it, to C. And so Herb Sutter now wrote CppFront, which translates C++ or Cpp2, like he calls it, to C++.
So yeah, I picked some of the slides to illustrate his syntax experiments. Declaration syntax in Cpp2 is left to right in the form of name
colon type equals value. Definitely reminds me of Scala. Another slide with
some sample Cpp2 code. The CppFront utility can use pure mode, which means
that there are lots of deprecated stuff
that's not supported out of the box, like macros, the entire preprocessor.
STUD module is implicitly imported under the pure mode, so you can use the standard
library right away without any additional preparation.
It's a modules-first, fast-build, strong ODR language extension, I guess.
He implemented his own paper.
Parameter-passing paper is about marking parameters with in-out and other annotations. He implemented an underscore wildcard and implicit template
arguments.
And also, he implemented optional return
for single expression functions.
So that leads nicely to the shorthand lambda syntax,
which many people still want for C++, but it's probably not going to happen.
Next slide was his medium term plans. He wants to complete the basic language.
Explicit template parameter lists that would support concepts.
Classes are not currently supported in Cpp2, so classes are planned, including user-defined
types, including defaults, explicit constructors, type invariants, completing contracts, and
some unification of operators.
I guess that's deducing this. Also planned are reflection, generation, code generation and meta
classes and also lightweight exceptions using std error condition like
this paper proposes. This is a slide with the problems that CPP2 solves compared with Cpp1 as Herb calls the standard C++. And it's a lot to read,
I'll have this screenshot in the notes. So to summarize, in Cpp2 core guidelines are the
defaults, left-right declarations of the form name, colon, type equals value.
References are not supported.
Herb really doesn't like them.
He says they were introduced for parameter parsing only.
Implicit imports that module.
Underscore wildcard.
Lambda is declared the same way as a function, but omits the name.
And that, with optional return leads
to the short lambda syntax
I don't know this fact about the reference
I don't see
the problem with that but the problem
with his approach is that
you know you don't have
references explicitly but implicitly
you still do and this time you need to know
which arguments are going to be passed by references and which are not have references explicitly but implicitly you still do and this time you need to know which
arguments are going to be passed by references and which are not going to be passed by it's a bit
like any you know like python or other similar languages some some objects are going to be passed
by value some objects are going to be passed by reference and now you need to know so you still
need to have the concept in your head it's not as explicit as it would have been, which I think is overall not as good.
Exactly, exactly.
If you remember Carbon, they also use some magic and say,
the compiler will decide how to pass parameters.
But yeah, I agree with you.
In the end, it's good to know, or maybe it's even essential to know what kind of parameter type you have even if it's
hidden by a compiler magic or this CppFront. Yeah, I know. I think most C++ developers
want to have control over things. They like knowing exactly what's going on.
Remember the discussions when the concepts were introduced?
We can't have short concept syntax because we need to know what the type is.
Yes. And now suddenly we don't need to do that.
That's, you know, it's gonna be swallowed by the same people, I don't know.
Yes, exactly.
But I think overall this approach, you know, even if he made a lot of good decisions, and
maybe I'm not discussing this, but how does he address the problem of evolution?
You know, when things need to change again, is he going to do CPP3?
Is he going to break the ABI?
Did he address this problem?
I don't think so.
I think it's just about the syntax.
He's not going to break ABI, I think.
Yeah, but even if he wants to break it again,
like he's going to change the syntax again,
he's going to do it in another 40 years only,
or maybe in 10 years he wants to change something else,
then what then yes
good point it's his personal experiment so anything can happen yeah but you know if he if he
went this way he wouldn't be on his personal experiment you know so then we still have to
solve the problem how to do any sorts of evolution you know well the the good, as you said, was that CppFront generates readable C++ code.
So in the worst case, it can just be materialized as C++ code.
I don't know.
I guess we'll see how this takes off.
In pure mode, there is no preprocessor.
What's interesting is order
independent syntax.
That means CPP2 doesn't
need forward declarations.
And it's implemented
by writing out
forward declarations automatically
in the generated C++.
Of course. That's nice.
Nobody wants to write forward declarations.
That's true.
But yes, but under the hood, it's just, you know, yes.
Yeah, there's no magic.
I'm going to write all the forward declarations anyway.
One thing I was curious to see was the operator colon equals.
Remember, Pascal?
I don't.
He didn't mention it explicitly, but from the source code,
I can deduce that it's for automatically defined variables.
So like in Python, you write a variable name,
then you write colon equals func.
And that at the same time declares and initializes the local variable with the return value.
I think that's something like that.
Universal function call syntax.
This means that free functions can be called as member functions.
So, for example, you can call vector.sSize to get a signed version of size
instead of going a size vector.
DC claims that it is also for tooling so that you can do object dot.
And I think it's a noble pursuit, but on the other hand, this is going to confuse the humans.
Because I would expect this function to be defined in the class of the object.
But then again, I don't know.
Maybe we only need the dolings.
The thing is, if you decide to use this in your project,
and you also decide to migrate your project gradually,
and you have mixed code, CPP2 and C++,
your brain is going to go into overdrive,
and there'll be lots of confusion. I mean,
you'll want to write C++ as Cpp2 and... I don't know. We'll see, I guess.
All typecasts in Cpp2 are done via as, which is part of the pattern matching proposal.
I guess that's not bad union is not supported use variant
all variables are initialized before use
null pointer is not supported
there is no pointer arithmetic
delete and owning raw pointers are not supported
unary operators are suffixes
that's really weird
when I saw this code it
looks really weird. To get an address follow the expression with &
So if you dereference a pointer you write pointer variable star and if you
want to get an address you write var &. That's really weird.
He did implement contracts. Good luck with that.
That's gonna change many times, I think, in the coming years.
Yes, what kind of contracts did he implement?
I think it's expected and expects and ensures.
So those ones that are kind of in the GSL, I think.
Yeah, yeah, you might be right. That's probably what he used.
So regarding parameter passing, there are out parameters.
Weren't they discouraged?
Looks like a regression.
I think he kind of does mention that, you know,
if you don't have to use the out parameter,
you use the return, just return the value. I think somebody was asking, but if you do need to use the out parameter, you know, use the return, just return the value.
I think somebody was asking, but if you do need to use the out parameter, then okay,
there is the out label, which I think is an okay idea.
There are other parameter annotations which are copy, in out, move, and forward. I think his idea is that these will make it simpler to reason about
what happens with the argument passed into such a parameter.
In parameters are automatically const,
and you don't need to choose between passing by value or by reference.
Yeah, we just discussed this.
You probably won't be avoiding that
variable capture using ampersand for lambdas post conditions and string
interpolation that's interesting regarding the generated C++ code no
discard attribute is the default okay that's probably a good thing.
Auto-generated forward declarations, like we said.
It's human readable, which is good.
And also it uses namespace Cpp2, which contains all this magic.
Regarding safety, Cpp2 compiler implements optional bounds checking.
You can run it with a special command line parameter and it will add
bounds checking code to anything that can be bound checked that has a like a pointer in size.
So yeah, that is interesting. During the presentation Matt Godbolt implemented CppFront support in Godbolt.
Was it during the presentation?
I mean, it was announced at the end of the presentation, and there was probably more to that.
But it was still very impressive.
There are quite a few discussions on Reddit.
I counted six.
Lots of duplicate threads. Let's do it! It's great! Though personally
I'm not sold on the unified declaration syntax, so it's like people will be happy
with some aspects of it and not happy with others. And the cycle will repeat. Someone won't be happy with CPP2. It's the
same with Carbon. They will submit a pull request, Herb will reject it, people will
be unhappy and will invent something else.
Yeah, as long as it's vague and the aim is let's make things better, let's break stuff.
You know, a lot of people will go for, you know, the low-discs will go for, yes, let's break the machine.
But then, you know, when this becomes the standard, you know, if it does, then people will just complain, you know, in the same way that they complain with the current standard.
This one writes, I think this trend of experimental C++ replacements,
val, carbon, CPP2, marks an inflection point.
There are smart and talented people that couldn't push through ISO.
They've had enough and are now looking elsewhere.
Well, this is not looking completely elsewhere, but it's a point.
And someone says, Herb Sutter is chair of the ISO C++ committee and he definitely will try to push this through the committee. Yeah, I'm sure some committee members look at this and say,
hmm, we'll see about that. So yeah, this was another thread. Some people are not happy with the syntax. The syntax is just a syntax.
So I'll have those links to the discussions in the show notes. But yeah, it's an interesting
development, one of many. I hadn't looked at the val language yet. I think it's by Doug Greger,
who used to be on the committee. Sorry. Is it also a Sean Parent experiment?
I don't know, maybe. Oh yeah, hang on. Yes, I think Doug Gregor joined Adobe, so that must be...
That would make sense. Yeah. So he went after... I think he was pushing for concepts, for the original concepts, the checked concept proposal,
and when that didn't pass he left C++ altogether and went to Apple to implement Swift,
but now he's back to C++ and maybe he's doing something like a new language replacement.
So yes, it's very interesting.
Let's briefly go to...
Oh yeah, this is the CppFront GitHub repository.
There's lots of information and motivation and such.
There are already several contributors.
There was a new mailing in September, and I'll briefly go through some of the papers.
There's quite a few at Revision 0, which is always interesting to me. What do people propose
that is completely new or mostly new? So this paper, function ref, a type erased callable
reference by Vittoria, Romeo and others. It looks like it's progressing pretty well, and I think it's targeted for C++26.
And that would be a good thing to have for parsing functions as parameters,
because that function is a bit too expensive.
This is basically how to avoid remembering how to define a type for a function.
Yeah.
Instead of going like, oh, let me Google again.
Where's the pointer?
Where is the brackets?
And then you can go function ref as a type.
So the advantages of this is that callable objects supported by this,
it takes any callable objects,
regardless of whether they are constructible.
Clean ownership semantics, it has reference semantics, minimal overhead, and that even
enables modern compilers to perform tail call optimizations. So yeah, good thing.
The next one I wanted to discuss was Proxy, a polymorphic programming library.
And we looked at this before, and I was like, hmm, that's a nice experiment.
And now I see that it's like at revision 9.
And also, I learned recently that the author of the proposal works at Microsoft.
So, hmm, that seems to be progressing.
Maybe we even get it in 26.
It's like static polymorphism,
but avoiding CRTP, I guess.
The next one was Universal Template Parameters
by Mateusz Pusch, Gaspard Ajman and others,
and Karantan Jabo.
It's at revision 3,
and they say it's been completely rewritten.
I just saw an email from the committee GitHub
saying that more work on this should be encouraged.
So I guess it's a good idea. This paper, it's a quote, this paper unifies the model of template
parameters with the model of dependent tokens, types, values, templates, and at some point,
hopefully concepts. This model is not uniform in C++23
because it lacks a way to treat all of the above uniformly,
ironically denying the ability of generic code
to treat itself generically.
And so basically, this introduces something
called template auto, which I guess is magic. We'll see how this goes.
Next one is standard secure networking.
This is at Division Zero, and the author is Niall Douglas,
who did lots of work on the standard networking previously.
So this is a proposal for standard secure networking based on the same concepts and idioms as his file handle and mapped file handle, which are part of his low-level file library.
Judging by the examples, it's a pretty good proposal, makes writing network code easier. But what caught my attention...
How does he address the problem of security fixes and patches? Does he cover that or not?
I hadn't read it in detail, so I don't know if he does. From the code examples, it's pretty
straightforward to read something from an HTTPS server.
But what caught my attention was that he doesn't mince words about the executor's proposal.
I think he might be biased.
Just a tad.
He says,
Neither asynchronous nor coroutine I.O. is proposed at this time,
and therefore this proposal has no opinion which concerns P2300 std execution.
I don't intend to propose any of that, like, runtime-pluggable,
multiplexer-setable-per-handle and so on, something, details.
I don't intend, he says, to propose any of that for standardization, because
P2300 state execution lacks the extra lifecycle stage needed for efficient generic stacking of
async layers, of which TLS over a million connections per kernel thread is a classic
example. P2300 state execution lacks, in my opinion, the hard guarantee needed
for efficient stacking of async layers, which is never possible dynamic memory allocation.
To add relevant detail, myself and the authors of P2300 disagree about whether dynamic memory
allocation can be given hard guarantees in the present P2300 design. I
say no, they say yes, and I don't think we can reach reconciliation.
P2300 remains an insufficient subset of the P2052 proposal for our needs, in my opinion,
as just aforementioned.
yeah... it doesn't shy away from confrontation this paper i guess. no yeah.
so the next paper i wanted to look at was member visit and apply.
this is just about making visit and apply member functions for a variant.
The author is Barry Revzin, and he says the goal of this paper is to add member function
versions simply for ergonomic reasons.
The paper adds no new functionality that did not exist before.
I guess we could live without it. Okay, existing and proposed sometimes
proposed looks a bit better. Fine. You know, maybe one of those that could go
through. Yeah. It's harmless enough. So the next one is allowing allocation in static initialization. That's an interesting one. That
would presumably somehow magically allow you to allocate dynamic memory in constexpr functions
and allow it to escape constexpr functions. That was entirely too much magic for me,
so I didn't read the paper. But the concept is very interesting.
It's quite mysterious, you know, I really want to know more about it too. magic for me so I didn't read the paper but the concept is very interesting.
So quite mysterious and I really want to know more about it too.
Yeah that warrants closer attention. And the last thing I wanted to show you was a link
to GitHub of Steve Downey who summarized C++ 23 status report for papers.
So if you want to know what papers and proposals are in 23,
that's a good source for you to read through.
Right, I think that's it for today.
I'll leave you with...
Oh no, hang on.
C++ Club got mentioned on Redditdit in this question any good podcasts about
c++ thanks jay karkinstall and yes that's going to be the tweet that ends today's meeting natalie
silvanovich writes don't let the perfect be enemy of the good. Don't let the good be the enemy of the okay.
Don't let the okay be the enemy of the kind of works maybe.
Right.
Thank you very much all for coming and I'll talk to you soon.
Bye-bye.
Thank you, Gleb.
Thank you.