CppCast - Design Patterns in Modern C++
Episode Date: July 19, 2018Rob and Jason are joined by Dmitri Nesteruk to discuss Design Patterns with Modern C++. Dmitri Nesteruk is a quantitative analyst, developer, course and book author, and an occasional conferen...ce speaker. His interests lie in software development and integration practices in the areas of computation, quantitative finance and algorithmic trading. His technological interests include C# and C++ programming as well high-performance computing using technologies such as CUDA and FPGAs. News Coroutine types Easy::jit Just-In-Time compilation for C++ Tool to recommend noexcept and constexpr Dmitri Nesteruk @dnesteruk Links Udemy: Design Patterns in Modern C++ Design Patterns in Modern C++ Design Patterns in C# Sponsors PVS-Studio February 31 Patreon CppCast Patreon Hosts @robwirving @lefticus
Transcript
Discussion (0)
Episode 159 of CppCast with guest Dimitri Nustrik recorded July 18th, 2018. Try the demo version today at viva64.com. co-routines and jitting C++. Then we talked to Dimitri Nostra.
Dimitri talks to us
about classic design
patterns with modern
C++ developers by C++ developers.
I'm your host, Rob Irving, joined by my co-host, Jason Turner.
Jason, how are you doing today? I'm all right, Rob. How are you doing? Doing good. We were just
talking about your C++ Now coming up, so do you want to share what you're working on?
Oh, my C++ Weekly episodes? C++ Weekly, I'm sorry. Yes.
Oh, do you... Well, I didn't expect you to ask that. Okay.
So I sent out a Twitter poll, and I said,
which way do you prefer to return from a function if it's multiple return paths or a single return path?
And I got like 880 responses to the poll.
I think it's like the most expensive Twitter poll I've done.
And that's with, I think, only one retweet.
It's just like my regular Twitter followers responding to it.
But yes, so my next episode of C++ Weekly, which will be on
Monday, as they always are, is going to say that there's actually only one right
answer to this question. So that should provoke some internet trauma.
Yes. Yes. We will see what happens.
Okay. It'll be interesting to watch that video and see what happens. Okay.
It will be interesting to watch that video and see what the answer is.
Oh, I guess before we move on from, well, that, I guess, talks and such,
I did get two talks accepted for CppCon.
Awesome.
And just a reminder, since I haven't mentioned it in a time,
I am doing one of the two-day trainings after CppCon a time, I am doing one of the two day trainings after CPP con.
Right.
You're doing one of the post training classes.
Okay.
One of the post training, one of those post conference training classes.
Yeah.
So, um, people should sign up for that.
It is on C++ best practices.
And are we already past early bird registration for CPP con?
I forget.
Um, it might. Oh oh i don't know they scheduled
the early bird registration to end after the results were sent so that people who had submitted
talks could still get early bird but i don't know if that's still going or not you know i i'm looking
at a post saying early bird registration ends this weekend and that was posted uh on july 6 so
i think it is over but everyone should still go ahead and register and look into some of these
pre and post conference classes if you haven't already yeah absolutely and i don't think early
bird affects the class prices i don't think so yeah i think it's just the conference registration
itself yeah and if you happen to live in the bellevue area and aren't going to CBPCon,
you're still welcome to attend one of the classes.
It's true.
Yep.
Okay.
Well, at the top of our sort of like three to piece of feedback,
this week we got an email from Shalom saying,
Hi, Rob and Jason.
After having become addicted to the show,
I've been working my way through the entire archive.
It's absolutely amazing how much C++ has changed since you started the podcast,
and yet so much remains relevant, even in the cutting edge.
Listening has been a blast,
and alternating between new episodes and older ones
really underlines how much the show has improved technically.
All the content has maintained the same excellence of quality throughout.
Thanks for making the show, and keep it coming.
I'm glad to hear that I think we have improved technically.
I know we got through a couple hurdles in the early episodes with pen clicking and noise and things like that.
Why does the pen clicking thing keep coming up?
No one has mentioned it in years.
I know.
But yeah, I'm glad you enjoy the old episode.
We do have a decent archive now.
And I never thought about this, how much the language has changed.
We fully covered the move to C++17.
Yeah, I mean, C++14 was still fresh when we started the show.
It was still fairly...
Yeah.
Well, part of the difference is how quickly organizations are starting to learn
that they need to stay up to date, basically.
Now, with all the training I've done lately,
I know that there's lots of organizations
that are limited by other things.
Like if you're producing a product
that's going into third-party distribution in some way,
you're going to be limited by whatever compilers
they say you're allowed to use on the hardware that
they're requiring you to write for. And that's holding a lot of people back. But people that
have control over their own tool chains, they are really trying to stay up to date.
Yeah. Yeah. Well, we'd love to hear your thoughts about the show as well. You can always reach out
to us on Facebook, Twitter, or email us at feedback at cbcast.com. And don't forget to
leave us a review on iTunes.
Those do help us find more listeners.
So please send us a review if you listen to us on iTunes.
Joining us today is Dimitri Nustruk.
Dimitri is a quantitative analyst, developer, course, and book author,
and an occasional conference speaker.
His interests lie in software development and integration practices
in the areas of computation, quantitative and algorithmic trading his technology technological interests include c-sharp and c
plus plus programming as well as high performance computing using technologies such as cuda
and fpgas meet you welcome back to the show thank you i'm glad to be back
hey dimitri with all this talk about lately, and we were just discussing a few minutes ago off air that I last saw you at C++ Now.
Are you planning to go to any upcoming C++ conferences?
No, no, I'm not.
To be honest, after five and a half years of nonstop traveling around the world, I'm giving it a break.
It's now been two years where the only travel I'm doing right now is maybe going to the Canaries for some extra sun.
That's pretty much it.
So no conferences for me for now, but I'm already kind of missing it a little bit maybe.
But I guess one of the key differences, and this is going to sound really cynical,
but one of the key differences is that back when I was an evangelist, somebody paid for all those trips.
And now I got to be very selective here.
But I wouldn't discount the idea of going to some conferences
at some point in time.
But at the moment, since it's not part of my job,
it's a lot more difficult to even prepare a talk
because I'm busy with other things.
Right.
Makes sense.
There's fairly large conferences in Europe.
I mean, there's Meeting C++ and C++ Russia, right?
Yeah.
Yeah, those are there.
And also I go to, well, I did go to a.NET conference recently, and I do visit the user
group meetings on the.NET side here from time to time, and even some C++ events, which
also a very active C++
user group here now that my colleague
Anastasia who you've also had on the show
she's now coordinating
the activities of the local C++
user group and there's like meeting after
meeting there so
I can't keep up with all of this
Wow
Well Dimitri we have a couple news
articles to discuss feel free to comment on
any of these and then we'll start talking to you more about uh design patterns and the book you put
out recently okay okay okay so this first one is a post on uh the abseil blog from titus and it's
about coroutine types and when i first uh saw this article, I knew that we have discussed this alternate coroutine proposal that someone from Google is working on.
And I thought Titus was going to be advocating that and comparing the Google coroutines with Gores coroutines.
But it's not really about that.
He mentions the Google alternative proposal, but he's really talking about the task class and how it, I guess,
doesn't really match what he sees as other standard library class conventions.
Yeah. Honestly, I wasn't able to get into this article as much as I would have liked to have.
Well, personally, I see that there is a great parallel between this and uh what's going on
in dot net and i hate to redirect things to other languages but essentially this road has already
been traveled in the dot net space and there is this async await paradigm that's already been kind
of tested out and implemented and even the name of the class is the same. So we have the task class in the TPL
and the.NET space, which actually is what effectively wraps a unit of work. And one
important thing that sort of comes to mind as I think about this is the ability to control
the thread on which a continuation actually happens. And the reason why this is important,
I'm sure that people in the C++ world will hit this sooner or later, is because sometimes you have constraints. So, for example,
you might have a user interface thread, and then you want the continuations to happen on this
particular thread. And in actual fact, in the C sharp language, there is explicit support for
this paradigm. And there is a lot of dark magic around this, because you can hit certain traps and they would sort of catch you
off guard as you sort of transition from sort of one unit of work to another. So this would be an
interesting area to watch out for in the C++ space as well. Yeah, I was also thinking about this and
comparing it with what I know about T and async await and.NET.
And one thing that Titus points out is if you return a task from a coroutine function and you don't call co-await on it, the task doesn't do anything.
It doesn't start executing.
And I don't believe that's the way it works in.NET if you return a task it is
executing and you can kind of check its state
and you don't necessarily ever need
to call a wait on it you can check its state
and you know later on checking
see that it's done and get results from it
and that doesn't seem to be the way
the C++
coroutines are going to work with GOR's proposal
well having a no op
is just a really unintuitive approach, I think,
because if somebody returns a task of T,
you really want to give the caller the option
to either call this synchronously or asynchronously.
That seems like the most sensible approach.
So having a no-op in this case instead is just very bizarre, to be honest.
Yes, maybe some more thought should go into this, as Titus is advocating for.
Okay, next article is EasyJIT.
And this is a library that brings just-in-time compilation to C++ code.
Interesting, we were just talking about the.NET comparison, and that's obviously something they have in.NET. But I thought this looked pretty interesting. I've never thought of
having JIT in C++, and the way they're doing it is, I understand you need to kind of poke
into a compiler, I guess, in order to do this? Yeah. Yeah, I think once again, what people really need is some sort
of compiler API. And by that, I mean, a generic compiler API that's part of maybe the standard
library interface, so that roughly speaking, what you could do at runtime is take an std string,
for example, at runtime, and then ask the compiler to basically, you make a program from that string, you compile
that program to, let's say, a dynamic library. Maybe it's an in-memory dynamic library. You load
that library and you get a pointer to the function that you just compiled. And in actual fact, if
once again, coming back to other languages, we've had this functionality in Java from the earliest
versions of Java, just being able to compile Java within Java. And of course, C-Shop does it as well. On the C++ side, you do get this from CUDA
of all places. So for example, if you want to compile a program for the GPU right from inside
an already running C or C++ program, you can do this. You can actually invoke the compiler through
the compiler API. But that's possible only because there is just one CUDA compiler.
There isn't a myriad of different compilers
that we have in C++.
I think a potential pitfall to getting this standardized,
something like this standardized for C++,
would be that not all hardware platforms
that are supported by C++ would this even be possible on,
because you can't
execute code from read-write memory and that kind of thing, depending on the platforms.
Yes, and furthermore, I mean, when you're compiling, you're compiling with a certain
set of flags, which might yield a different result. And we already have this, you know,
in numerics, for example, you compile for different C++ compilers,
and you find out that you have to have different epsilon values on different platforms
because the way that the floating point calculations are compiled is not uniform.
It's not exactly one-for-one.
Right.
Okay, and then, Jason, do you want to introduce this last one about noexcept and constexpr tools?
Yeah, I just saw this question on Reddit whether or not there was any tools that will tell you if a function could be constexpr or noexcept.
And I thought, that's used to doing lots of tooling around C++ that actually, in one of my classes,
wrote a quick program that was able to tell you if a function could be constexpr, which I thought
was pretty impressive. I don't know if that ever will ever become public. So I definitely had an
interest in this. And it's interesting discussion on Reddit. But the main fallout for me here is
that there are already static analysis rules in Visual C++ that will tell you if a function could be constexpr, could be called as constexpr, and can tell you if something should or could be noexcept.
Yeah, so is that part of the core guidelines, or is that just existing C++ warnings?
Some of it falls out of core guidelines. Yeah. So I think another area where obviously
tool support people should jump in here and all those static analyzers like ReSharper C++ or
the equivalent tools, they should be able to somehow navigate through this. But personally,
I think that whenever you go into the territory of analyzing a particular trait
out of a potentially infinite set of invocations, because here you have to traverse the whole
call tree and so on, in many cases, you end up with a situation which is almost unresolvable.
So for me, for example, one of the things that I would want to have in, you know, hypothetically is a feature which would tell me
for a given calculation, what tolerance should I compare floating point values with? And it turns
out that this is a rocket science kind of problem. It's not a problem where you can just go ahead and
solve. You can solve it on a simple example, like you add 0.1 and 0.2, you know their floating point
representation. So when you compare them to 0.2, you know their floating point representation.
So when you compare them to 0.3, you know the tolerance more or less, you know the epsilon.
But in the general case, what you end up doing is you end up fiddling these values.
So it's kind of like an experimental procedure.
It's like you're performing experiments on your code before you actually put it into
production, which for me was always, you know, it's one of those things I don't like,
because I do like experimenting on, you know, actual data, say market data, for example,
but experimenting on compiler output, just for the sake of, you know, fiddling these values,
it seems very painful. But unfortunately, at least in my case, I don't think there is a
possible solution for this at all, because it's just too complicated. But for the const, specifically, I mean, going back to the article for the constexpr case,
knowing whether or not a function can be constexpr, this is something that every compiler
already has to implement. Because in C++17, the call operator on a lambda is constexpr if it meets
all the requirements of being constexpr.
So every compiler that supports C++17 has to have the capability of analyzing a function to know if
it can be constexpr. Just have to call that on every function instead of just on lambdas,
and then spit out that analysis to the programmer. Well, okay, one question is,
how costly is this analysis? has to see if there's any inline assembly, it has to see if there's any throws state, no, it has to see if there's any try statements. And it has to see if it is calling any other function that is
not constexpr. So it should not be terribly costly, it already is going to know if every other function
call is constexpr or not. Okay, well, it's an it's an interesting idea. And I think we've had
we've gone through the process of using the compiler as a static analysis tool.
Because if we look back at, let's say, the F-sharp language a couple of years ago, the way the whole language implemented its static analysis is by effectively running the compiler kind of behind the scenes.
And that was really slow so uh i personally i think the the best solution is
still to get the tool makers to do something about this because that way first of all they
will be able to figure out the performance implications because some things are just
too too costly to analyze and it's it's sometimes sometimes you have cut off points so you have a
certain depth to which you can analyze and then you have to cut things off and not analyze further because simply there is no CPU time anymore. So if this is a trivial
analysis, then I'm sure the developers in, let's say, ReSharper C++ will implement this at some
point. And if this is non-trivial, we'll have to see. Maybe it can be just a separate static
analysis stage that you can do not related to compilation.
So you might want to, let's say,
run it on the continuous integration server
and look at the results once a day
and then adjust based on that.
Right.
Okay, well, Dimitri,
so a couple episodes back,
we had Kevlin Henney on the show
and talked a little bit about C++ design patterns.
And I think you actually commented on that episode saying you actually released a book
recently on design patterns.
Do you want to tell us a little bit about the book?
Yes, I did.
In actual fact, I wrote two books in parallel.
So one on C++ and one on C Sharp.
And both of them are now published on LeanPub.
But with the C++ book, what happened is I've been contacted by A-Press,
which is a publisher.
And so they are now the publisher of the C++ Design Patterns book.
Now, the books themselves, they are based on online courses
that I made for Udemy in this particular case.
In actual fact, I have four of them.
I'm covering C++, C Sharp, Swift, and Java.
So eventually,
maybe all of these courses will become into books, because for some people, it's more convenient to read than to watch. But I have both of these alternatives available. Interesting. Do you
want to tell us a little bit about the topics you go over in the books? So essentially, I'm going
over the classic design patterns from the Gang of Four book with very, very few modifications.
It's actually interesting because if you think about, you might think that patterns would actually change from the 90s when the original book was published.
But in actual fact, not much has changed.
And further, if you look at all sorts of different programming languages, they all operate around pretty much the same set of patterns, despite their differences in syntax and whatnot. And I think this is a
testament to the fact that the original catalog of the design patterns is very robust. So in other
words, it's a really good selection to begin with. So what I do in my books is I basically try to
find all the latest ways, so all the kind of applications of the latest versions of the programming languages
and how you can implement design patterns using those languages
and what are the caveats and what are the alternatives, that sort of thing.
So what do you see as the role of design patterns today in modern programming?
Like how should we be applying these things?
Well, on the one hand, we have to state that design patterns, they're no longer some sort of
panacea they once were. So there was a time when I was just starting out in the industry where you
really needed to know design patterns, like really well to pass a programming interview. And right
now, you're kind of expected to know things at the general level. So if somebody, like, you need to be able to
figure out what a factory is, but it's not so important anymore. And also, you know, nowadays,
for example, if we're talking about IDEs, you might come up to an IDE, and it will give you
an option to refactor a constructor into a factory method, for example, and you need to be able to
know what this does, basically. But in terms of using design patterns in programming,
I think they're as relevant as ever.
And it's just that we're not talking about them so much,
which is okay, because, well,
I guess the hype has died down a little bit,
and we can just focus on applying them
and obviously refining their implementations
as new language features show up.
And we don't really see them as a silver bullet anymore.
So they're just a practical side of development overall.
And, you know, in my opinion,
design patterns would make a great course
as part of university education.
Because, I mean, currently the situation
with the way that computer science is taught
is, in my opinion, quite dark
because nobody really focuses on
the practical aspects. And people do rudimentary programming, they typically take, I don't know,
the basics of Java, they do have a data structures course, but they don't learn what the industry
needs. And that includes things like how to debug, how to profile code, how to write unit tests,
and of course, design patterns and stuff like that. So that's one area where I would be interested in maybe seeing more stuff related to design patterns.
Interesting.
That's an interesting point.
I definitely agree.
Universities should be doing more to train software engineers, not necessarily computer scientists.
Well, you see, because over a decade ago, I went through this sort of
undergraduate computer science, and you get these subjects like formal methods, for example. So,
essentially, on the one hand, it's part of computer science as an academic discipline.
On the other hand, as you graduate, you realize that the only way you're going to be using formal
methods is if you go and work for NASA, which has a completely different kind of process for designing software. If you don't work for NASA, if you work for the
99.9 recurring percent of the industry, then all you've just learned is basically useless. So you
can stay in academia and do even more work on formal methods, for example. You can go work for
NASA or you can go and, you know, sort of work in the real world, so to speak.
I want to interrupt the discussion for just a moment to bring you a word from our sponsors.
PVS Studio is a static code analyzer that can find bugs in the source code of C, C++, and C-sharp programs.
The analyzer is able to classify errors according to the common weakness enumeration,
so it can help remove many defects in code before they become vulnerabilities.
The analyzer uses many special techniques to identify even the most complex and non-obvious bugs. For example, data flow analysis mechanisms, which is implemented in the tool, has detected a
very interesting bug in the protobuf project. You can read about this bug in the article February
31st. The link is under the description of this podcast episode. The analyzer works under Windows,
Linux, and macOS environments. PVS Studio supports analysis of projects that are intended to be built
by such common compilers as Visual C++, GCC, Clang, ARM Compiler, and so on. The analyzer
supports different usage scenarios. For example, you can integrate it with Visual Studio and with
SonarCube. The blame notifier tool can notify developers about errors that PVS Studio detects during night run by mail.
You can get acquainted with PVS Studio features in detail on viva64.com.
So do you want to give us some examples on how newer C++ 14, 17 features affects some of the design patterns that you go over in the book?
Well, I have to say that in my book, I don't really focus much on language versions.
So if I happen to use some later feature, like make unique, for example,
or if I make a basic string literal using the s both fix,
I don't stop in the middle of a book and say,
ha, here we're using C++14.
And the same goes for library features, obviously.
So if I use std any or std optional,
I'm not going to pause and sort of make a note of it.
But obviously, all of these things,
sometimes they make the code concise.
Sometimes they significantly change the approach.
But generally, I don't spend much time discussing the implementation of patterns in earlier versions of C++.
Because after all, the book is called Design Patterns in Modern C++.
So basically, I'm sticking to the latest version of the language available.
And I'm using the latest language and the latest library to implement these particular patterns. It's also very difficult for me to distinguish
because I don't have a mental recording
of which C++ feature comes from which version.
I'm more practical.
I have the liberty of using the latest,
obviously the latest production version.
And so I don't even catch that moment
when I'm using something like some variatics with constructor forwarding or fold expressions.
I just use them because I know how they work, and that's pretty much it.
So you just kind of assume that the readers will have at least some familiarity with the newer C++ features?
Well, yeah.
I mean, I'm not making an introductory book here.
I'm showing implementations of standard practices,
and I will use whatever tool is available.
So there's plenty of literature on modern C++ as is,
and people can look things up there,
and obviously plenty of wonderful screencasts online as well.
So I'm just trying to complete the picture, so to speak.
Okay, so I'm going to attempt to see if I can get a specific example from you, though.
Since you mentioned standard NE, that was added in C++17.
Some people, when they're exposed to it, they're like,
this seems like a solution looking for a problem.
They don't see the practical use case for standard NE.
And since you just mentioned it don't see the practical use case for standard NE. And since you just
mentioned it, is there any particular use case in your design patterns book where you are using
standard NE that you could talk about? Well, yeah, I think one of the locations where I'm using it
is when I'm talking about the interpreter pattern and the fact that, well, let's say you're trying to interpret a programming language,
which, you know, you have a class and the class can consist of various things,
like you can have a function inside it, or you can have, let's say, a member variable inside it.
And there are different ways of handling this variability.
So you know that there's going to be a node in there or a collection of nodes of some type,
but you want to keep things flexible. So
there are different options here. One is obviously you would use inheritance. So you would have some
base interface that both a function and a variable expose, and then they get stuck in here. But if
you look at, let's say, instead of hand rolling the library, you decide to go for Boost Spirit,
for example. So Boost Spirit is a library which just helps you build these
parsers. And Boost Spirit
actually leverages static polymorphisms.
So in this case, instead of
defining some sort of base interface,
you just have
your any type
and, you know,
then you write specific visitors
so that you know how to actually
traverse the whole thing, so to speak.
So that's one example.
Okay.
Okay.
What would you say is one of the most important things that a C++ developer should know about design patterns?
Well, from the practical perspective, I suppose it just helps being aware of patterns at a high level.
Because that way you kind of,
you recognize an opportunity to use a pattern later on.
And there's really no need to memorize implementations, obviously,
because honestly, that's what books and online courses are for.
And you can always just go online and look up
how someone has implemented this or that pattern
and then decide if it's the right way for you.
I will say this, though,
there are situations where a pattern-first approach does, in fact, help.
So, for example, let's suppose you're building an abstract syntax tree.
Maybe implementing the visitor pattern from the outset is a good idea
because, after all, you know that you're going to be traversing this tree.
You might be sort of traversing and collating the elements of this tree
into a string or something.
So you can do this in advance. And the same applies to kind of more general scenarios, shall we say. So let's say
you've got a component which has a fluent interface. So you have methods which return this
or return star this. Now, this is all well and good. But if you want other people to be able to
inherit from this component and still preserve the fluent interface behaviors,
this requires you to adopt a completely different approach to how the entire class is implemented.
So these are some of the examples.
So you already mentioned that you have Udemy courses
around other languages with the design patterns.
And you said you, let me just make sure I got this right,
parallel wrote C Sharp and C++ versions of this book?
Yes.
Okay. So in your experience of working on these Udemy courses, if I got this right,
you have Swift, Java, C sharp, and C++. And in earlier years, you said that you want to avoid
like trying to compare languages, but I would like to invite you to compare languages right talk about the good stuff in C++
and then we can discuss some of the stuff where it can improve.
So in terms of where pattern implementations are better in C++,
it's mainly to do with two things.
So one is obviously multiple inheritance
and this idea that whenever you want to add functionality to a class,
you don't have a situation where the base class is already taken, and you have to mess with
interfaces because you have multiple inheritance. And also, you know, sort of as an add on to this,
C++ actually allows you to inherit from a template parameter. And this allows you to create a
situation where you make an inheritance chain just by nesting several
different templates typed together. And then, of course, you know, the magic of C++ kicks in,
and you start doing all sorts of wonderful stuff. Like, for example, you've constructed this type,
which like A inheriting from B inheriting from C using this kind of inheritance. What you can then
do is you can program your code so that if you pass this type constructor arguments, these constructor arguments are going to be distributed across all of the different base classes.
A typical example would be that of a decorator pattern, for example.
And to somebody not familiar with C++, this would just look like magic because nothing like this exists in C Sharp or Java.
And in fact, taking this to a higher level, templates in C++ are a lot
more powerful than generics in other languages. I mean, things like variadic templates, for example,
you only get them in C++. So for example, in a language like C Sharp, you know, your generic
arguments, they need to be constrained in order to be usable. So if you have a generic argument,
T, for example, you can specify that it have a generic argument, T, for example,
you can specify that it has to have an empty constructor, for example,
but you cannot specify that the constructor
actually takes one argument
and that argument is an int.
Now, in C++, obviously,
without constraints and concepts,
which I guess we're going to be getting in C++20,
you can still use that constructor
and provided you feed it the correct type, it will work.
Whereas in a language like C Sharp, that's not even a possibility.
So you cannot, for example, just call an arbitrary constructor with two arguments.
Unless, of course, you use reflection, for example.
And of course, C++, for example, gives you more options with regard to managing the lifetime
of the class generally. So you have the stack that gets cleaned up automatically, gives you more options with regard to managing the lifetime of the class generally.
So you have the stack that gets cleaned up automatically, and you have the various smart pointers,
which effectively ensure that as you kind of pass the object around, it does what you want.
And you also have things like deterministic destruction, which if you have it, if you're used to it,
you don't notice that you're getting any benefits.
But as soon as you jump to a different language where, for example, a subscription to an event can actually generate a de facto memory leak because you're keeping a reference to it and the garbage collector is kind of holding on to everything that you subscribe to and so on.
And you don't have deterministic control over it and you end up building additional structures on
top of that that's something that once again this is an illustration where c++ is great on the other
hand yeah there are lots of places where c++ would really need to kind of improve its game i mean
the first is obvious so from the perspective of just general usability,
I'd say keeping the declaration and definition
in a single file is probably my number one wish
overall in C++.
And I mean, this whole business of messing around
with includes when you've got complex dependencies
between types, it's a dark art, honestly.
Sometimes I have like a piece of paper
and I draw the little arrows
so that I can figure out what
depends on what so then I can get my includes correctly. So in this regard, like many other
people out there, I do want modules. But unlike all those big corporations, I don't really care
about where the macros are supported in modules anyway, because as I understand, that's what's
kind of holding up the whole process. And I mean,
it feels like if we get modules, then the standard library would have to still require some sort of a
rewrite, at least a partial rewrite, if modules are to be supported. And I mean, personally,
I'm prepared to live without the macros. I can just, you know, take the macros, I don't need them.
So one more thing that we need is obviously libraries and library usability.
Ideally, some sort of, I don't know, it seems like science fiction,
but some sort of STL2 proposal that changes the way that APIs of fundamental data structures,
so that they're kind of more intuitive to use.
So for example, if you look at the erase, remove idiom,
that's a good example of something
that's completely wrong with C++.
And because it's on a purely linguistic level,
you expect erase to wipe the entire container.
And if you look at erase in the C sharp containers,
guess what it does?
Yes, it erases all the contents of a container.
But in C++, there is lots of this magic,
lots of these magic moments that you need to be aware of. And I think that,
especially for, you know, once again, getting people into the language, they're going to see
this and they're going to think, oh my god, I have to keep 100 of these special cases in my head in
order to be able to actually work with the language. What else? Well, reflection, obviously.
So having reflection,
or at the very least, some sort of metadata being published from types, this would allow,
for example, proper unit testing instead of the kind of macro-based hackery that we get in
Google Test and similar libraries. And reflection would also allow lots of little things, like we
have the prototype design pattern, which is all about copying objects.
And if you have reflection, this allows you automatic serialization of plain C++ types,
which means you don't have to write your own serializer code, because reflection could go
through all the fields, and it can serialize it automatically. So this is something that would
simplify, for example, the prototype design pattern. It will basically allow you to deep copy objects, including all of their dependencies.
You'll just be able to take a type, serialize it, digitize it in memory,
and that's your copy, essentially.
And there's lots of other stuff, like in C Sharp, we're used to extension methods.
So having extension functions in C++, that would be really cool.
So basically, the idea is that, you know,
you can take a type that's already defined, and you can give it additional members that lie elsewhere, like on the side, for example. And there's been proposals in this area for a while
now in C++. And this idea is also related to another interesting idea, which is partial classes.
That's the idea of being able to have the definition of a class
in more than one file. And this allows you to, let's say, having one part of a class that you
wrote yourself and another part which is made through code generation. And it's still the same
class. And right now, the only way to do this in C++ is obviously to use inheritance. So these are
some of the examples I could go through more. But essentially, I think
that the overriding idea is that C++ designers and the committee, they should not be afraid to
look at other programming languages and steal ideas from there. Because a lot of those ideas,
they're already tried and tested, they work, there is no problem. And I mean, things like
properties, for example, that's likely to start a holy war.
But properties are really useful.
They're really useful.
And we have these two camps.
We have the sort of pragmatist camp that say,
well, properties work in C Sharp,
they work in Kotlin,
they work in other languages,
why not just have them?
And we have the other camp,
which is like the purity camp.
And they're saying, well, you can do anything
using your own sort of library approach.
Just make a property type and work with that. So I'm more in the pragmatist camp than the purity
camp, I'm afraid. So one of the comments that I actually never get this from students or very
rarely, but I see often on Reddit or Twitter or whatever, is people saying basically that
C++ is willing to take any idea from
anywhere and just glom it all together, and the language is too big and complicated already.
Now, just for the record, I'm not saying I disagree with you that we should be willing
to adopt some of these other ideas, but do you have any comment about that?
Like, do you think we risk making the language too complicated?
Well, I think in C++ the story is not the same
as with other languages. So, for example,
take C Sharp. C Sharp is expanding, but
it's still C Sharp. In C++, what we
have is we have several parallel realities.
We have the conventional C++
reality, we have
macros and things that you can build
on top of them, like the boost
preprocessor magic. We have
the template
reality where you can do a lot of things with template on top of them, like the boost preprocessor magic. We have the template reality
where you can do a lot of things
with template metaprogramming and whatnot.
And I think really the problem is the spinning out
of these additional realities,
additional kind of chunks of the C++ universe,
which don't exactly relate to one another.
So you can obviously can sort of you can
obviously mix and match that's the whole point but they they kind of they require to you to know
several different disciplines so maybe on the one hand the uh the language gets bigger but i think
that uh you still have to be pragmatic if something is proven to work in another language, then why not take it? I mean,
why not? Yeah. One thing worth mentioning is, I don't know if we've talked about Herb Sutter's
Metaclass' proposal in a while, but that's something that, you know, might be able to
provide certain features from other languages, you know, like interfaces or properties,
if I recall correctly. Yeah, yeah, that's also a possibility.
But once again, the thing with metaclasses
and the thing with this kind of what I would call proper metaprogramming,
because template metaprogramming is a bit like hacking the preprocessor,
but proper metaprogramming can be implemented in all sorts of different ways.
And the way that many people see as the correct way is obviously
exposing the compiler API. So essentially, you can write a meta definition, which takes an
existing class. And for example, using, once again, the compiler API goes through every field and
generates an additional field for that field or something to that effect. So that's one approach.
But if you look at the deprogramming language, the deprogramming language doesn't mess around.
It doesn't bother with any of that. What it does instead is the following. It says,
we're going to have this mixin instruction, which is going to be like a string returning function,
but it's going to be called at compile time. And at compile time, whatever this string returns, we're just going to paste verbatim right inside the class and then compile
the whole thing. And to me, even though this is kind of a brute force approach, it seems like
the most simple approach that people would actually use, because it's a lot easier to
understand the string than it is to understand, for example, some specific, because you need
language constructs for mixing parts that you want to generate. Like, for example, if you want to
generate a field, this consists of the fact that there is some data structure called a field there,
but also you have to provide the name. So you have this quasi quotation syntax, and we've seen it in all sorts of languages on the.NET side as well. And they,
they are, I mean, it's a, it's a doable problem. It's a problem that you can implement. However,
it's complicated and it's a lot easier for most people. I would say 99% of people who actually
want to use metaprogramming to sort of generate something at compile time,
they would either just spit out a string,
and you can spit out a string using something like what D gives you,
or simpler yet, you can use T4, for example, in Visual Studio.
That's just a code generator.
That's just something that you can write instructions in C Sharp,
and it spits out whatever you want.
So it's a templating language.
So I'm not sure about providing compiler-like APIs because, well, maybe I am kind of underestimating
my fellow man, so to speak.
Okay.
Dimitri, is there anything else you wanted to go over before we let you go uh one thing i
want to mention is it looks like your udemy course is currently on sale if listeners are interested
in checking that out well udemy's whole paradigm is that everything is always on sale all the time
that's that's how they make money so pay no attention to to. Courses are always there. And I guess all I want to say is check out my courses, check out my books and, you know, enjoy design patterns. And, you know, these are in 10 or 20 years' time, when we have C++20 or C++30 or whatever, I think we're going to have the same catalog of patterns.
I don't think anything is going to significantly change.
Certainly what you see is you see some programming languages kind of uptake the patterns right inside the language itself.
So, for example, in C Sharp, that's obviously the observer pattern that's just been embedded into the language.
But overall, I think the catalog that was in 1994
when the original book was published,
I think the catalog is as relevant
and it will stay relevant in the future.
Now, what I can do from my side
is I can keep updating the books
and I can keep updating the courses
so that if you look at C++, for example,
you're always going to see the latest implementation.
So as we get C++ 20, you're going to see maybe me using concepts
whenever they are relevant.
So that's my promise to you.
Okay, so we'll put a link to both the original Design Patterns book
by the Gang of Four and to your book.
And if you're interested in learning
about those design patterns
with more modern coding examples,
definitely check out Dimitri's book.
Okay, well, thanks for coming on the show again, Dimitri.
All right, thanks for having me.
Yeah, thanks for joining us.
Thanks so much for listening in
as we chat about C++.
I'd love to hear what you think of the podcast.
Please let me know if we're discussing the stuff you're interested in. Or if you have a suggestion for a topic, I'd love to hear what you think of the podcast. Please let me know if we're discussing the stuff you're interested in.
Or if you have a suggestion for a topic.
I'd love to hear about that too.
You can email all your thoughts to feedback at cppcast.com.
I'd also appreciate if you like CppCast on Facebook.
And follow CppCast on Twitter.
You can also follow me at Rob W. Irving.
And Jason at Leftkiss on Twitter.
And of course you can find all all that info and the show notes
on the podcast website at cppcast.com.
Theme music for this episode is provided by podcastthemes.com.