C++ Club - 160. C++ Bookcamp, WG21 April mailing, Contracts, Rust, Circle
Episode Date: April 23, 2023With Bjarne Stroustrup, Frances Buontempo, Gianluca Delfino, Joel Daniels, VladimÃr ArnoÅ¡t, Ivor Hewitt, and other colleagues.Video: https://youtu.be/9JGWjK6UWdANotes: https://cppclub.uk/meetings/20...23/160/
Transcript
Discussion (0)
Welcome everyone, this is C++ Club Meeting 160, and we have our first guest today.
Frances Bontempo joins us. She's a software engineer and consultant based in the UK,
the editor of ACCU's Overload magazine, and her About Me page says that she can program
her way out of a paper bag in a variety of ways.
Frances is writing a new C++ book, so do you want to talk about it?
Yeah, sure. So I'm writing this book for Manning.
It's in their early access program at the moment, so they're five chapters up.
The sixth one's going through review at the moment.
I've focused it on people who used to know some or even lots of C++,
but have maybe got left behind by some of the recent standards that have been released.
So I'm going to have nine self-contained chapters.
The first one's just an overview, and then after that they've each got projects in, including six, which is in the pipelines, allows you the opportunity to code
your own way out of a paper bag using some random number distributions. I think this is a skill
everyone should practice at some point. Yeah, so this is the Manning book web page. It's currently in early access. There are several versions of the
book. It's available in a variety of formats. E-book, print, e-book is kindle, epub and pdf.
Plus, interestingly, something they call a live book. It's basically a web version and it's very convenient in the sense that
it's got all the links. And the most interesting part is there is a live book discussion forum
where readers can discuss the book as it's being written, which is a new way of writing
books I guess.
That's allowed some people who are reading it to
leave comments as well saying, could I do it like this instead? So I've been engaging with
some people who've bought it. That's been quite useful, having the quick feedback.
And of course some people who are reading through spotted better ways of doing things than me, so
we've all learned something. Yeah, it's an interesting way of getting feedback, definitely. Quote from the book,
C++ is an old but evolving language. You can use it for almost anything and will find it in many
places. In fact, C++'s inventor, Bjarne Stroustrup, described it as the invisible foundation of
everything. And regarding the target audience, quote,
this book is aimed at people who have used a little
or even a lot of the language
and lost track of recent changes.
It's nice that the live version of the book
has a copy button for code snippets that you can try.
And also I liked that whatever external information or website you are mentioning, there is a link to that, which is really, really useful.
Maybe a small thing, but thank you for not using std endl in the example code.
Yeah, I have a rant about that, and I'm not the only person.
If you want a new line, ask for a new line.
If you want a new line and flush the buffers and do loads of other things,
okay, knock yourself out.
But if you just want a new line, use a new line.
Yeah, I don't think I've used it for a decade and a half.
I think there might be a misconception where people think that if you use std endl,
it provides us a magical cross-platform way
of ending the line, which is not true, really.
One question I had was,
how long did your internal debate last
on whether or not to write another book on C++?
Or was it like a spontaneous decision, I'm writing a book now?
It was a mixture of looking at my huge pile of C++ books and going, there are a lot of books but what has actually happened was I'd reviewed a book for Manning
with lots of tiny C projects in and I thought despite my huge pile of C++ books none of them
have got that kind of small self-contained projects and I remember reading I think
Koenig and Moos accelerated Accelerated C++ ages ago
and finding that really useful.
So I actually got some small self-contained examples
just to get you the hang of the basics.
If you wanted deep dives into precisely
what was happening in the background,
yeah, go for the big stack of books.
And I've not seen anything like the accelerated C++ recently that
just goes look here's a few small things just to give you that leg up so you can then do the deep
dive afterwards and then I said to myself no fair to say don't write another book you're far too
busy and but I'd already volunteered by then so it was too late so yeah it doesn't cover in depth different
versions like c++ 17 or 20 or so on and everything if you want to know everything you'll need to read
all the other books but like I said it's just aimed at people just want that little self-contained
get yourself up and running a bit. So get you started again.
Right. Yeah, makes sense.
I especially liked one thing about the book that while discussing
a particular task
in a chapter, the book
explains all the aspects of C++
needed to solve it, like
going here and there and
covering various topics
as opposed to dedicating a separate chapter
to a single C++ topic that most other C++ books do.
And this, to me, feels closer to how C++ is used in practice.
So it's like a simulation of, you know,
a frantic Googling when you want to solve something.
So I think that's very good.
If you try and write code to do one thing you've learned,
you usually end up having to do something else,
like write to a file or read some input or something else as well.
And then you go, oh, I could have done it in ranges.
So despite the title chapters,
there's several other bits in
every single chapter just that all fit together into the one project life's like that isn't it
indeed well uh thank you very much for talking about the book and um yeah everyone go and check
it out and i'll be reading it as it's being written,
which is a bit of a new experience.
But yeah, very interesting.
Thanks.
Right.
This is your blog.
This is a very good ACCU Overload magazine
that I make sure to read whenever a new issue comes out. It's very good.
And this is your Twitter account. Oh, you're on Mastodon. Yeah.
I'm on Twitter myself.
Fair, yes.
Right,
so
a bit of a feedback
on earlier feedback.
Last time
we talked about
Roy Barkin's
comments
on
the earlier video
on YouTube
about a paper
on using
auto curly braces X
for DK copy
due to which it couldn't be used
for the proposed short concepts notation. And the paper seems to have been accepted,
plenary approved for C++ 23. This is the paper by Zhihao Yuan and it proposes auto
parentheses x and auto curlies x for transforming X into a PR value with the same
value as if passed as a function argument by value.
So it's basically a DK copy.
And we weren't sure last time if it was accepted or not, so it looks like it is. And this is the GitHub page for the paper and it has the C++23 tag.
There was an interview and
Ask Me Anything session with Bjarne on the Exorcism
YouTube channel and it was very interesting. The chat
was pretty
active and the questions were interesting, so I encourage you
to go and check it out. Obviously there were some silly questions in the chat like
what do you think of Rust and what about chat GPT and Zim or Emacs And why is C++ so hard?
But there were some good questions too.
I never saw that list of questions. I only heard the ones that were repeated to me by John.
Yeah, luckily he filtered all the chat.
It's more or less a requirement these days
when I give an interview
that somebody relays. The idea of keeping track of all the questions and then choosing the right ones
is just too hard to do in real time with answering other questions at the same time.
Yeah, it's definitely the work of the host, not the interviewee.
It gets much better as a conversation when that's done that way.
Yeah.
Right.
So April mailing has dropped and there were quite a few papers
and I wanted to look at some of them. The first one is
revision one of the paper Do Expressions. It's by Bruno Cardoso Lopes, Zach Lane, Michael Park
and Barry Revzin. Apparently there is prior art for this. GCC has had an extension called statement expressions for decades, which look very similar
to what we are proposing here, they say.
GCC extension uses a combination of parentheses and curly braces to designate a block or statement
expression.
But the proposal differs from this in two critical ways. The first is the
ability to specify a return type, which is critical for allowing statement expressions to be values.
And the second one is the ability to support yielding out of different branches of if,
due to the implicit nature of the yield.
So yeah, hopefully this progresses well, and we get it, maybe in C++26.
I haven't read this proposal, but I'm excited about it, because I've frequently been forced
to create a lambda function and call it immediately an anonymous lambda
to emulate this.
And the syntax is rather horrible.
And usually it's about keeping local variables
sufficiently local,
being able to declare something
and then know that it will go out of scope fast enough.
Yes, this is very exciting.
Next is Uniform Call Syntax for Explicit Object Member Functions by Gaspare Ajman.
Quote, this paper introduces a unification of hidden friends and explicit object member functions to allow a limited but hopefully uncontroversial uniform
call syntax for them. Unlike the previous proposals on this topic, this one avoids pretty
much all controversy." I imagine committee members seeing this and going, I'll be the judge of that.
I have never seen an uncontroversial proposal. There's always
somebody who objects to something. Yeah, so this is the example code. Basically, you define a
friend inside the class declaration, like a hidden friend idiom and then you'll be able to call it as a member function
or as a free function so that's that's it the proposal only applies to this hidden friend idiom
the next one is Trivial Infinite Loops Are Not Undefined Behavior by JFBastion.
Quote.
C and C++ diverge in their definition of forward progress guarantees and have done so since
C++11 and C11 added a memory model and acknowledged that threads exist. C does not
make iteration statements whose controlling expression is a constant expression undefined
behavior, whereas C++ does. C++ implementations therefore assume that even trivial infinite loops
must terminate. This is unfortunate because using an infinite loop is a common idiom in
low-level programming,
particularly when a bare metal system or kernel must halt progress."
So this proposal is about making trivial loops, not UB.
And they define trivial loops in a certain way. I don't know exactly how they are going to
distinguish between trivial and non-trivial loops but I can see that it's...
I mean in my early days I did program for a small embedded system like a
payment terminal and there was an infinite loop that ran everything
basically. So I can recognize it as a problem. How did the program interrupt? Was there some
sort of signal and the external button being pressed or something? Yeah, I think it was interrupt-based. It was a long time ago.
Perplexed about the premise, is it true that just writing while true asks the user do you
want to quit? If the user says yes, break? Is undefined behavior right now in C++?
No, I don't think that's what it claims, right? It can be.
I think the progress is required, so the code must end at some point.
So infinite loop is a UV. Maybe if the compiler can demonstrate that in no case the if becomes true,
and then in no case the program will break,
then there is a problem.
But otherwise, I think it should be fine.
The problem with it, I think, is that if the compiler cannot demonstrate that it's not UB,
then it just assumes that there's no UB,
and optimizes it away.
I think so.
So, yeah, tricky.
There are programs that in principle runs forever.
And the way you stop them is to disconnect them from the power source.
Yeah, but that's also UB, isn't it?
Well, such things exist for good reasons.
Next is Contract Violation Handlers by Joshua Byrne.
Quote,
Custom violation handlers turn an overly simplified contract facility that is highly ineffective in many environments
into a moderately flexible and practicable one.
In short, I think this adds a contract violation handler semantics back to the minimum contract
proposal which currently doesn't have it. And it says the C++20 contracts
prior to their removal describe a conditionally supported mechanism for
installing a user-supplied contract violation handler
with appropriate semantics.
And the paper says that handling contract violations by a user-provided callback
is an established, well-tested approach that is deployed in many modern assertion facilities.
But the current MVP has no mechanism for altering the behavior on contract violation
and as you may remember there are only two options either contract conditions are not evaluated or
they evaluated and any violation terminates the program as you, I don't think the minimal viable proposal is viable because of the absence
of alternatives to termination.
And I have not read this version of this paper, but it's plausible.
I mean, the general approach is plausible, and the devil is in the details.
Yeah.
So the next paper is trying to explain the idea behind the contract's MVP by Andrzej
Krzyminski.
And it sort of tries to justify the contents of the MVP, including the fact that only two
outcomes are provided, and it tries to validate the fact that there's no need to supply any more
options and everything can be added afterwards. But in practice, it's going to be tricky. And this is what the next
paper is about. Next paper is called Unconditional Contract Violation Handling of Any Kind is a
Serious Problem by Ville Wutilainen. Quote, this paper explains why we shouldn't have hard-coded eval and abort and
eval and throw modes in the contract's MVP and further explains why we should have a violation
handler instead. For those in a serious hurry, go read Joshua Byrne's paper, the one that we just
mentioned. In this paper, Wille argues that adding more options
afterwards after the MVP
is
accepted might not be
even possible that is it will
theoretically be possible but
in practice as Bjarne
said many times if you
link against the program
that only has two of those options
then you basically are stuck with
that. And there is no guarantee that your program will not abort at some failed contract violation.
You may not always have an option to recompile everything with the new contract flags. So in
this particular case, it looks like this needs to be done right from the
start. There's a sort of a political reality that is if you give people half of something,
then some people are satisfied with that. And then the number of people who will support it goes down because they've
already been satisfied, and the people who think that the original was enough will be
against it.
And so I think it's actually a disingenuous argument, unless we are in a very specific situation so that there's no controversy about the
potential extension and all of the potential extensions here have been shown in the worst
possible way to be controversial yeah as experience shows, contracts is a very controversial proposal.
The MVP, for instance, I would have to object to any use of it in the standard library,
because that would instantly make the standard library useless to, I think, significant number of application areas.
So I guess I'm new to this debate. Maybe someone can enlighten me a little.
What's the two use cases? I understand one use case of contracts is to help prevent undefined behavior. And in that
use case, the assumption is every contract violation will certainly lead to undefined
behavior. An example of such an implicit contract today is the brackets operator on the standard
vector. And in that case, your two modes are I trust I have
no undefined behavior, so I'll ignore. And I don't trust I have no undefined behavior, so I'll
terminate so as to prevent undefined behavior. That seems like a very limited use case, but I
understand it. What's the use case where you're using contracts to protect from something
that isn't undefined behavior and expect happy recovery?
Don't think happy recovery is a good description. What a contract should guarantee is that you
don't pass it. That is, you don't get into the state that will come after the contract
and therefore get you into trouble. And there's three ways of getting out of that.
One is to guarantee at compile time that the program will run.
The second is to terminate, and the third is to throw an exception.
And the most common response for throwing an exception is clean up and exit or reinitialize or write a log message and terminate or re-initialize, something like that.
The thing that, in my opinion, mustn't happen is to carry on beyond the point of the contract that has failed.
But the Bloomberg people claim that that's actually an essential use case.
That is, they want to log and continue.
I'm not so sure about that, but that's another situation where they claim
that you never get your contract right the first time in an existing
program and therefore you want to use them as a debug mechanism the way some people
use a garbage collector as a debug mechanism to find leaks. Got it. So basically,
sometimes you use contracts to prevent undefined behavior, like I said.
Other times you use contracts to stop before you would cause
undefined behavior, and you can trigger exceptions and destructors and
stack unwinds and things to terminate only a piece of your program
to avoid undefined behavior.
Other users want to use contracts as a mechanism not to prevent undefined behavior but to prevent
behavior they don't like. That's true, but also to prevent undefined behavior by not getting to it. Yep. So the time travel
has to be stopped somehow.
Right.
There was a proposal we discussed previously
that suggested separating your program into components,
and each component could be terminated separately
without affecting the rest of the program.
That was supposed to help with the termination option
of contract violation handling.
That would have touched an enormous part of the language and an enormous
number of existing programs yeah
right there is a reddit thread on the mailing and the first question is what is going on with
reflection for something that's supposed to be a focus
for the next three years
I see very little movement on it
compared to executors
someone says
the SG7 mailing list looks dead
five emails in a year
is not inspiring
and
SG7 didn't have any telecons
as there was no paper addressing SG7 didn't have any telecons as there was no paper addressing SG7.
And the group did not meet.
So it's a bit depressing.
Nothing happens unless somebody drives it.
And the people who were driving Reflection basically walked away from it. And I think most people who could have taken
over are busy with other things.
Hmm, that's very unfortunate.
There is some discussion
on including algebra,
linear algebra, in the standard
with different
takes, like
there's no place for it in the standard versus it
it should be in the standard.
The usual.
Someone compares it to graphics and they say that graphics wasn't properly defined or something. Whereas linear algebra, BLAS-based for example, pretty much
exists already and it would be good to have it in the standard.
Next, someone posted on Reddit, stop comparing Rust to old C++
quote
people keep arguing migrations to Rust
based on old C++ tooling and projects
compare apples to apples
a C++20 project with Clang-Tidy integration
is far harder to argue against
in my opinion
and actually it's a refreshingly calm discussion on the
pros and cons of both Rust and Borden C++. For example, pros, quote, there is a lot
that Rust has going on for it that C++ 20 does not have, leaving out the
usual memory safety and thread safety language features that people are
probably aware of already. Build system stuff and dependency management and even packaging for
simple enough apps are basically a no-brainer in Rust. Coming from C++ this alone is life-changing.
Moves are destructive, so there is no use after move, no fuzzy moved from state.
Pattern matching as a language feature is incredibly powerful,
and it's not bolted on after the fact, as it maybe will be in C++, but the language was designed
around it. And for me it's a point of envy. I'm looking forward to pattern matching.
The quote continues, most defaults that people often
wish were different in C++, starting from constness and barring surprising implicit
conversions, are fixed in Rust. Unit and integration testing is also part of the language,
and unit tests can be put next to the code they test. And for the cons, quote, As someone who uses both Rust and C++ near daily, I always miss C++'s type system in Rust.
Rust type tools are very weak by comparison, and the fallback macros are a royal pain.
I've been working on an archetype ECS entity control system library for games.
This is essentially a processing engine for arbitrary
tuples in struct of array data structures. The lack of variadics and the weakness of trait
expressions, no specialization, no negative constraints, combined with the orphan rule,
has made it pretty unpleasant to do it in Rust. If I want the work to be done at compile time for runtime
performance reasons, I'm basically stuck with one giant mega-crate containing all of the code in
question, created by very heavy proc macros. Most popular ECS libraries in Rust rely on a lot of
RTTI and reflection-like functionality that isn't zero overhead. The equivalent library I've written in C++
is almost entirely compile-time, with variadic tuples and tuple processing functionality,
like using Sphene to find all types in a type tuple that have a given function. Rust synoms
are great, but Rust generics are nowhere near as powerful as C++, and that weakness is compounded by Rust's strictness and coherence,
the orphan rule, and lack of any duck typing."
There are much more interesting and useful comparisons in the thread, without hyperbole
or too much emotion.
But the usual caveat applies.
Don't go too deep or too far into the thread, or you will encounter the increasing
amount of C++ bashing and Rust propaganda.
Consider this, quote, I also feel that people who just come to RCPP to advocate Rust are
newcomers who completely fail to understand the purpose of Rust.
And obviously there is this one.
Quote,
You can smell the fear around here these days,
says that person about RCPP.
My eyes are stuck.
The next one is Circle.
We've touched this before, but I wanted to revisit it, because there were some new posts about it. Circle is a new C++20 compiler. It's
written from scratch and designed for easy extension. This is its
home page. This is the github page with documentation and issues, and this is the reddit thread about it.
someone posted on reddit, it is absolutely insane to me that one guy has both made his own c++
compiler and has also added some awesome compiler extensions to the language like native shader compilation. There was a new post on Reddit by Sean Baxter, the author
of Circle. The post is titled C++ Evolution vs C++ Successor Languages. Circle's feature
pragma lets you select your own Evolver language. And this is obviously a response to all the supposed successor languages to C++,
including Cpp2 and Carbon. And this is Sean's answer to that. So circle feature pragmas let
you kind of build your own evolver language syntax. Someone replies to it. Having a facility to make source breaking changes
so that the language can evolve. Awesome. Having a knob for every feature so that everyone can
design their own dialect of the language. Pretty bad, I think. I mean, it's bad if you want to
actually have a community around it, because then nobody knows what you're talking about.
But maybe this tool isn't supposed to be just that, at least.
Maybe the main purpose was to experiment, and I think it's an amazing tool for that.
So, sounds good to me.
Someone said to that,
works fine in other languages. Here is all the extensions you can enable per source file in GHC
Haskell compiler. I once talked to somebody who had a new language. And the aim was to allow everybody
to extend and improve the language
so that you got the ideal language for every application.
This was done by facilities for modifying basically the AST
so that you could have your own syntax
and your own semantics for everything.
And I spent about two hours trying to explain to him that if he had his ideal language
and I had my ideal language, nobody else could use both of them. And in particular, we couldn't communicate because sending a piece of data from the one to the other, there was no guarantee that it had a semantics that was defined.
And you actually have to have a pretty rigid language that is shared by everybody before they start extending it. And a lot of these suggested improvements,
especially if they're optional,
and especially if they can change the semantics of existing code,
goes in that direction.
And therefore, I get worried about it.
One of the strengths of C++, and probably even more so at C, is that the meaning of
code doesn't change.
This person says, I never heard any Haskeller around me complain about it.
Haskellers around me.
The picture of John Travolta looking around. These fighting words from Sean
Baxter go like this, quote, would you rather have the features you want or
would you rather deny others the features they want? We're at an impasse in
C++ because the standard for changing anything is consensus. This is
impossible in most cases. We should let
institutional users who sponsor tool development lead the language in directions that they want
it to go in." Ah yes, institution-specific C++ versions. What could possibly go wrong there?
A redditor points out an important detail.
But Circle is not open source.
Someone replies, unfortunately, this is a killer.
No company is going to want to use Circle to build millions of lines of source code
when it can seize development at any time with no recourse.
Two observations here. The reason C++ was standardized under ISO leading to advantages and problems was that that argument was implied, was specifically stated by IBM, Sun, and HP to me.
And that's how we got into that.
Now, Sun with Java proved that this is not true.
You can have a corporate language and if you hand out enough goodies for free, people will
give up their principles and just use it.
Rust started as a company-specific language also I think it was started at Mozilla
as a way to program the Firefox browser
and only then it sort of developed into a Rust foundation
and this thing also is very important
someone says about Circle
that might be cool
but will remain an academic exercise
until there is Windows support.
So, since it's not cross-platform, many people can't use it either.
Right, Herb Sutter posted, it's quite a while ago actually,
CPP2 design notes, universal function call syntax, const, unsafe and ABI.
Basically design notes for the design decisions that he took when working on Cpp2, which I
don't hear much about lately.
I don't know.
It was in the recent CppCast episode.
Oh right, I hadn't listened to that yet. Yep, that's true.
I need to work on my CppCast backlog.
There is also a Cpp2 design wiki, which is useful, it contains all the design information, and the reddit thread.
This article, will Carbon replace C++?
Is that one of those questions in the title where they answer?
That rigid law holds up as usual. This article written by Manuel Rubio is written as if
Carbon is already a language that's available, which is not exactly the case.
And basically it reiterates everything that was said in the presentation about carbon. The Hacker News thread on this notes
that basically many comments express doubt about the title.
Basically, the quote goes like this.
C++ just doesn't have that many real problems.
It has a lot of irks.
What the problems people run into
are problems that others already solved
a thousand times over the last half century in many different ways, for many different iterations
of the language. Pretending you can replace C++ is like pretending you can replace cars.
Not just create electric vehicles, but straight up replace cars. Good luck, you won't succeed if
that's your goal. So hopefully you realize you need to focus
on making a decent language that some folks might consider using instead of C++ for some of their
work, instead of creating the successor to C++." This is an interesting tidbit, not exactly C++
specific, but it's an illustration on how various memory errors can be mitigated.
And it's about a virtual memory subsystem on iOS.
Quote,
On 64-bit Apple platforms, the entire 4-gigabyte 32-bit address space
is not accessible by the process,
which catches both null pointer dereference bugs
and 64 bit to 32 bit pointer truncation bugs. So yeah, I thought that was an interesting way of
just preventing the entire class of... Null pointer etching was common in the early days. All the Solaris systems
did them and I think some of the PDP-11s
did.
I mean C++ has grown up with that as being
a terminating error.
Not anything else. a terminating error. Not
anything else.
Right, so that's not
exactly new then.
Isn't it a case
that in some
embedded platform, actually
you can use address
zero as a proper
address?
Maybe on some microcontrollers?
Yeah, I mean, a lot of embedded zero is the jump address that then jumps the entry point
of your firmware.
Also, there's always somebody that can do it.
It's just whether it's protected for normal user-level code.
If there's a kernel, it can usually get there.
Yeah, pretty much all memories start from zero.
The question is whether the memory is free for the application
or whether there's any system data or anything else.
So it's fine, but for example, on Linux,
the first four megabytes are also unmapped
to cache all the null pointer
dereferences, just the same way as the iOS.
It's very common.
I think this was true in the 80s.
I was just going to say that I think the ability to have a program terminate when it
dereferences a null pointer has gotten worse over time because the optimizing compilers keep getting smarter.
So the termination may in fact happen someplace where you don't expect.
I've certainly done things like accidentally tried to call functions with a null this pointer and been very confused for a while because I get several method calls in before I discover what's going wrong.
Yeah, that's bad.
And came as a surprise.
It's been quietly coming out of core without any votes.
I don't remember voting for time travel and its implications of stuff I haven't actually looked at much.
So I had lots of compiler and IDE news. Visual Studio 2022 17.4 is available. And handy explainer article about Microsoft C++ versions. So we
have 2022 as the name of the Visual Studio IDE. The actual version of the IDE is 17, I think.
The compiler is 143. So yeah, pretty confusing. And this article is supposed to clarify that.
But they keep using it, and it's not like they're going to
switch to an ultimate version number like, for example, CLion did.
And Visual Studio now has CMake debugger as well as CLion. It allows you to debug your CMake scripts,
which is going to be pretty horrible, I think.
Someone said it's a build system configuration generator debugger.
Lol.
I wish I had it on VS Code, for instance.
I don't know if there is a way to get it with an extension,
but it sounds like a pretty useful feature to me.
I keep having to put messages in my CMake to find out where I did wrong.
Yeah.
I think that's all for today and I'll leave you with this post on Mastodon.
Dave Rahadja writes, overheard from a program manager when talking about project status
reporting, watermelon status, Green on the outside,
but actually red on the inside. And next one is a new book from O'Reilly. Essential copying
and pasting from ChatGPT. And subtitle is Deploy deploying untested code at breakneck speeds.
Right. I think that's it for today. Thank you very much for coming and I'll talk to you hopefully
soon. Bye. Bye.