Algorithms + Data Structures = Programs - Episode 308: Rule of N with Jason Turner

Episode Date: October 16, 2026

In this episode, Conor and Ben chat with Jason Turner about his Rule of N talk.Link to Episode 308 on WebsiteDiscuss this episode, leave a comment, or ask a question (on GitHub)SocialsADSP: The Podcas...t: TwitterConor Hoekstra: LinkTree / BioBen Deane: Twitter BlueSkyAbout the Guest:Jason is host of the YouTube channel C++ Weekly, co-host of the podcast CppCast, author of C++ Best Practices, and author of the first casual puzzle books designed to teach C++ fundamentals while having fun!Show NotesDate Recorded: 2026-10-07 Date Released: 2026-10-16CppCast PodcastList of All Jason's TalksRules for Special Member FunctionsThe rule of three/five/zeroC++ std::ignoreSpaceship operatorwarrenreconditesesquipedalianIntro Song InfoMiss You by Sarah Jansen https://soundcloud.com/sarahjansenmusic Creative Commons — Attribution 3.0 Unported — CC BY 3.0 Free Download / Stream: http://bit.ly/l-miss-you Music promoted by Audio Library https://youtu.be/iYYxnasvfx8

Transcript
Discussion (0)
Starting point is 00:00:00 And even without the multiplicative increase from those terms, there's still a dozen or more, is it? Yeah, and there's the ones, again, no one thinks about these. So copy assignment operator. Your options are by value, by value, by reference, const reference, volatile reference, or const file file reference. That's for the parameter, right, the right hand side of the argument. But you can also reference, you can L value reference or R value reference, qualify it. So that's three different states there because unqualified L value or R value reference qualified. And then you can also qualify it as const volatile, const volatile or unqualified, right?
Starting point is 00:00:55 Welcome to ADSP the podcast episode 308 recorded on October 7, 20206. My name is Connor. And today with my co-host Ben, we chat with Jason Turner in part two of this three-part conversation. In today's episode, we talk about Jason Turner's rule of N talk that he gave both at CPPCon and NDC Techtown. Well, maybe we should talk about some of these talks. I know that Ben had specifically called out this rule of N, which I'm assuming is alluding to the rule of one, three, five, although it could be a different rule that happens to be.
Starting point is 00:01:39 It is, okay. So maybe, I'm not sure Ben, if you have a question or, or, well, why don't we ask Jason first? What is the rule of N? What does the talk cover? The talk? I wanted to give kind of a modern update on like the rule of zero and five, basically, right? And like, well, okay, Ben, you don't like, I think this is fair to say.
Starting point is 00:02:00 You don't like things that are default constructible. Is that a safe-ish? I don't like, I was thinking about this this morning in preparation for our conversation today. And yeah, let's go with that. I have a whole lot to say on that. But let's, yeah, let's park that for a minute. So at the very least, you have opinions and you think, look, if your thing's going to be default constructable, there should be a reason why it's default constructible. Is that fair?
Starting point is 00:02:24 I think that's fair. For sure. Okay. But most people don't even don't think about default constructability, right? So I'm just like, okay, so let's talk about, let's take it to the rule of six, right? Which you don't, like, okay, if you go look at Howard Hennett's, like articles on this stuff, yeah, he talks about the default constructor also as one of the special member functions. because it is one of the functions that the compiler will create for you if you don't do anything to get in its way. And, you know, okay, so I just thought I would do that.
Starting point is 00:02:50 And then I'm like, well, like, I kind of want to make sure that I forget what road I went down, but I'm like, I kind of want to make sure that I cover like all the possible things that can impact the rule of five, right? So for the sake of our listeners, if you write a destructor, copy constructor, move constructor, assignment or move assignment operator, then those impact the other special member functions that are generated. So if you provide a copy operation, then the compiler does not generate for you the move operations. But if you provide the move operations, one or the other, then the copy operations are implicitly deleted.
Starting point is 00:03:33 And there's like a big difference between not provided and deleted, right? Like this, anyhow. So I started to go down this rabbit hole and I'm like, well, what are we? all the different signatures that the compiler thinks is a copy. One of the special member functions? Yes. Okay. And I think now I have to double check this.
Starting point is 00:03:57 That was, I have to, oh, shoot, I have to go back and look at my numbers. Because there are, so just to restate what you just said, there are, for example, considering copy construction. Yes. There are, you can write the copy constructor signature in potentially a number of different ways that the compiler will know that, yes, this is considered the copy constructor. Yes. And the copy constructor itself has, well, if you can default arguments on the copy
Starting point is 00:04:27 constructor, let's just throw that topic away because you have infinitely many copy constructors if you can default them. So whatever, ignore that. But most people don't know that there are actually, oh, crap, I'm going to get these numbers wrong. There's a lot of signatures that count as distinct overloads that the compiler will count as copy constructor. So it is, it is non-const reference, which no one thinks about of the same type. Right. The parameter is a non-cons reference.
Starting point is 00:04:58 Right. Non-cons reference, which is famous. So the regular one is the parameters a constant reference. That would be the one most people reach for. That's what most people would reach for, but the compiler is willing to generate one for you that takes a non-conser reference. Okay. In the case that the sub-objects of your type themselves have copy constructors that take non-constreferences, the compiler is going to generate one for you that takes a non-constreference. Oh, right. No one thinks about that, right?
Starting point is 00:05:25 So non-cons reference, const-reference, volatile reference, const-file reference. Those are the valid copy constructor signatures, the things that are actually different overloads, right? And move construct. But that can be expressed also. Also as a template perhaps, so there are other ways to write. No, if you make it a template, then it does not impact the rule of five. It has to be a non-template function. As far as the generation of the other special level.
Starting point is 00:05:52 It can be no accept or otherwise. It can be no except, but that is a distinct type, but that does not affect overload resolution. So I kind of tried to focus a little bit on like what things specifically affect overload resolution. But if you include a no accept. So I don't know how far we want to go into this. But like, spoiler alert for the copy assignment operator, that if you include also constexper, consteval, no accept, and I think no discard or not, something like that,
Starting point is 00:06:22 there's 320 different ways of spelling a copy assignment operator that the compiler will account for you as you provided a copy assignment operator. And like, what? Right. And even without the multiplicative increase from those terms, there's still a dozen or more, is it? Yeah, and there's the ones, again, no one thinks, about these. So copy assignment operator. Your options are by value, by value, by reference,
Starting point is 00:06:49 const reference, volatile reference, or const file file reference. That's for the parameter, right, the right hand side of the argument. But you can also reference, you can L value reference or R value reference qualify it. So that's three different states there because unqualified L value or our value reference qualified. And then you can also qualify it as const volatile, const volatile or unqualified, right? Whatever the multiplication is about. To be fair, qualifying, qualifying an assignment as const has niche value only. You tend to see it in DSLs, I'm going to say. In DSL, well, someone in the audience pointed out that stood ignore does that. Okay. Yeah.
Starting point is 00:07:36 Good example from the library. Yeah. So does this mean that that Howard Hinnett table that anyone that's seen, there's a number of talks that reference it? I don't actually think I saw the original Howard Hinnant table. I just, it floats around in the C++ community. Is what you're saying is that like there's a higher dimensional version of that. Yes.
Starting point is 00:07:56 Where all of these qualifiers. And so like if you thought that table was bad, that is but the surface of like, it's not even like a hypercube. it's whatever, an end-dimensional thing where these things interact. And is that the point of your talk that, like, hold my beer? You think that table's bad? Like, it's way worse than that. Well, that wasn't the point of my talk.
Starting point is 00:08:17 That's just where I started and then I accidentally went down this ridiculous rabbit hole. I've spent, I don't know, on the order of probably over 40 hours of research on this talk. And I never expected that to happen. Like, I just kept going. Like, what is happening? And then the point of the, okay, so, the point is, oh, let's just do a modern take on that. But then I also wanted to add the spaceship operator in,
Starting point is 00:08:39 because the spaceship operator has its own concerns. Like, it's not a special member and that the compiler will never generate something, a comparison operator for you unless you ask it to. But it can. So then I started playing with the rules of, okay, what things can be defaulted or not? And just for the record,
Starting point is 00:08:57 you can default the reference qualified assignment operators, and you can default the, you can default the copy constructor that takes a non-constreference, and you can default the copy assignment operator that takes a non-cons reference. Both of those can be defaulted unexpectedly. Anyhow, now it's like too much information in my head. Now, like, if a student asked me a question about one of these things, I'm just like, and then I try to go into simplified mode because it's not too much.
Starting point is 00:09:25 All right. You were getting to the point that aside from special members now, since C++ and seemingly continuing, the compiler is now able to generate more functions like equality, like spaceship, like maybe post-fix increment, is it, in C++? In C-plus-29, I don't know. 29. C-L-S-plus-29 that was approved post-fix increment, post-fix decrement.
Starting point is 00:09:51 It can be defaulted if you provide the prefix versions of those. But the other rabbit hole I went down is like, okay, say you explicitly equals default the spaceship operator. What does that give you? And this becomes like a trick question. Unexpected. It depends. No, no, no, if you explicitly defaulted. That's always the other. Well, the return type is its depends.
Starting point is 00:10:15 So, yes. So it would be member-wise, spaceship. Yes. And the return type would depend on the return type of the spaceship on the sub-objects in some way. Correct. But let's not... I mean, the easy version is like if they all have the same return type, But it's some common type of those. Yeah, it's the common type of the return types of the sub-objects results of their spaceship operators. But I'm not even worried about that part.
Starting point is 00:10:42 I mean, like, you have the spaceship operator, you've equals defaulted it. Let's just say, hypothetically, you wanted to take a pointer to the less-than operator. Can you? Oh, well, the less-than-operator doesn't exist. So maybe no? It doesn't exist. I don't know. You're going to now tell us.
Starting point is 00:11:01 Yeah. So the less than offer... You can still take... What is the actual wording? It is usable. Okay. Okay. Can you take the pointer...
Starting point is 00:11:10 Yeah, you can write the expression A less than B. Right. Okay. Can you take a pointer to the equality operator? Well, I don't know. And if the answer is different from can you take a pointer to less than... It is different. Of course it is, right?
Starting point is 00:11:26 Because if you explicitly default the spaceship operator, the equals operator is implicitly defaulted. But the rest of them are usable. I'm doing air quotes for those of you who can't see me. They're usable in air quotes. All right. So if you have an equals operator available in code that was pre-C++20, and now you compile it in C++20 mode,
Starting point is 00:11:53 you implicitly get not equals. That's neat. Thank you, C++20 for implicitly giving me not equals. Yeah. But that implicitly available, not equals, that is also usable. That is not actually existing, right? So I can't take a pointer to the, anyhow, it was this rabbit hole that just kept getting deeper and deeper and deeper.
Starting point is 00:12:14 And so you might have reasons for explicitly defaulting all six equality operators. If, relational and equality, yeah. Yeah, yes, all the comparison operators. You might have a reason for explicitly defaulting them all if you want them to be, like, actually exist, not just usable. Right. It's just, I don't know. So what's the answer to the question? So what is the answer to the question?
Starting point is 00:12:44 Can you take a pointer to operator less than if you have defaulted operator spaceship? Oh, no, no, you can't. Sorry. That function doesn't exist. You can't. You can't. You can use it, but you can't take a pointer to it. I see.
Starting point is 00:12:56 Yeah. Yeah. Because the compiler is not generating that function. it's doing something like rewriting expressions or trying rewrites of expressions. It rewrites it, yeah. And just in case anyone's curious, if you do explicitly default it and then you take a pointer to it and you call it, it is internally going to call the spaceship operator and then check to see if it was less than. Right. Okay. So the compiler's implementation of that equals default, which would route to the
Starting point is 00:13:22 spaceship. But you can't default. Like if I wanted only less than, hypothetically, I cannot just equals default that. I have to default the spaceship. And then what I would actually have to do is equals default spaceship and then explicitly delete the other ones if I wanted the compiler generated less than, hypothetically. The talk just became a giant rabbit hole. That's all. Like, there's just so many little nuanced details to this that I had no idea. And it was an interesting ride. Yeah. I may have released some of the rabbits on Jason a couple of months at the talk. He did. Because when Jason said, you know, I'm thinking about doing this rule of N, modern take,
Starting point is 00:14:05 I said, and something I had recognized in my code is a lot of times I follow the rule of zero, right? Which is just a lot of things are just plain structs and it's the rule of zero. But equality is important in a lot of places where you, so effectively it becomes the rule of one. You want to provide equality. And which can be defaulted. So that's one of the rabbits that Doug this Warren. Yeah, that's right. Yes.
Starting point is 00:14:31 Yes, you did that. You caused part of that problem, and then you caused the rest of the problem when you asked me something about whether or not they can be, if the right hand side can be, or the left hands, whatever, if the operator itself can be const qualified or something. You brought that up, and I said, oh, crap. There's like a multiply of three for all of these now again. Yeah. Anyhow, what was the reaction in the audience after you'd given the talk? I think it was a good reaction at CBPCon. I gave the talk of CBPCon and in DC Techtown.
Starting point is 00:15:06 I think it did a better job at CBPCon. And I feel like it was a good reaction. I think it made people think. And I think one of the main, like, practical things that came out of this, and I've talked to other people about it since then, is like if you have something like a strong wrapper around a floating point type, there's a very real possibility that you would want to explicitly default the spaceship, and then explicitly delete the equality operator, because that's considered problematic
Starting point is 00:15:37 anyhow. So make your user of your library do something more explicit. Just, I don't know. The TLDR of this thing is like think before you write code people. I mean, exactly. This whole thing, I have a class in my codebase which deals with wrap around. Right. So the original use case was like you have a microcontroller, it has a 32-bit unsigned register that is time that is continually incrementing microseconds, let's say. And of course, that can wrap around and when you measure time, you need to know what's in the past and what's in the future. You need to account for that wraparound. And so quite reasonably, I wanted a class that could encapsulate that. And so the comparison operators on the class do the appropriate thing for the wrap around of the unsigned value. Right. And for that class, I delete operator less than.
Starting point is 00:16:33 Right? I spell it differently. I have like, I think I call it cum less or something. But I delete operator less than. The reason I do that is that when you have a wrap around semantic like that, your less than operator is no longer transitive. Right. Right. Because it's like rock paper, scissors, right? It's non-transitive. And that means that if you naively pass it to, yeah, you know, A beats B, B, C, C, B, C, B, C, B, A. right? If you have a wrap around space, your less than operator is of that form, which means that if you try and sort things naively withstood sort, you're passing it comparator that does not adhere to what it requires.
Starting point is 00:17:10 Right. Which means you technically have undefined behavior at that point. Yeah, see, I'm fully on board with this, and I think that's a perfect example. Like, yeah, think. Like, it doesn't make sense to just blindly provide all of the operators. Selectively delete some of that would make sense for your problem set. or maybe selectively enable only the couple that do make sense for your domain. And also, like, I have had a recent discussion with other friends about this,
Starting point is 00:17:36 and many of them disagree with me, because they're like, oh, well, everyone knows if you provide the other constructors that you don't get a default constructor. And I'm like, you know what? No, I've reached the point in my life where if I don't want the thing default constructible, I'm going to explicitly default, delete that default instructor. Which is always. You know, like explicitly delete the default constructor.
Starting point is 00:17:59 Don't let, don't make, don't require the reader of your code to know all of the intricacies of how the special member functions are generated. Be explicit. Right. Because as you've just talked about and demonstrated, that is a very deep rabbit Warren. It's a Warren. It's not just a hole. It's a whole. Not just a whole.
Starting point is 00:18:20 It's a whole network of tunnels. The whole civilization under there. What is Warren? W-A-R-R-E-N? Yeah. Yeah, you know, where rabbits live. That's a new word. A whole colony of rabbits.
Starting point is 00:18:32 I have to be honest, I only know that word because I read the Kevin and Cal comic strip. It's old. It's been around forever. I don't know that. I was going to say, that's not a different word for Calvin and Hobbs, is it? No. Kevin and Kell is probably the, I think they advertise themselves as the oldest webcomic, oldest continuous webcomic.
Starting point is 00:18:48 I don't know. I discovered it maybe, I don't know, 15 years ago or something. And I went back and I read the entire archive. So I've read now all things. Holy crap, 31 years of it? I was going to say, if it's the oldest web comic, it must have started of mid-90s. 95, yeah.
Starting point is 00:19:04 Good gracious. That's before Connor was born. No, no. I was but a wee lad back then. Warren, I'll add a, I don't know, dictionary link to some online dictionary for those that are in my camp. I was watching an interview the other day on John Stewart, and he kept on throwing out these words,
Starting point is 00:19:24 and I was like, if I was the inner being interviewed, I would have to ask every second question. Like, sorry, can you define that? Like, I felt so bad for the, I assume the interviewee, his vocabulary was larger than mine. But I can't remember a couple of the words. I was like. But John Stewart was being unnecessarily. Yeah. Recondite and Cisquipedalian.
Starting point is 00:19:44 Okay. Well, Ben would have gone toe to toe. He would have come back with that big word and said that stuff. Because I definitely don't have those in my dictionary or vocabulary. Definitely in my dictionary, not in my vocabulary. What were the two words you just said? Reckendite and something... I was joking.
Starting point is 00:19:59 Sesquipedalian? Is that a fake word? No, no, I think it means prone to using long words. Oh, I thought... In extreme form, it runs to Hippapodontor-monstrus sesquipidalian, I believe. Wow. When you said you were joking, I thought you meant like it was super-califragilistic, expialidocious, like that kind of thing, like a made-up word.
Starting point is 00:20:22 But no, you were joking. No, they're real words. They're real world. Words. All right, well, listener, there'll be a couple more dictionary entries if you want to look at some online dictionary definition of, I'm not going to try and pronounce the second one or the third one. That was impressive.
Starting point is 00:20:37 Impressive, I guess that's what you, have those ever come up in your, what do they call them? Oh, you know, these are just things you learn from a lifetime of geeking out on word games and things like that. I was going to say, yeah, does this come up in cryptics? Like, because that's probably, uh... Well, long words don't tend to come up across. very much because they just... No.
Starting point is 00:20:57 You know, a crossword is at maximum, and a crossword entry is 15. A crossword grid is 15 by 15 as a standard. So you don't tend to get very long. In fact, it's rare to get even a 15 left. Usually top out about 11, 12, maybe 13. Be sure to check these show notes, either in your podcast app
Starting point is 00:21:12 or at ADSP the podcast.com for links to anything we mentioned in today's episode, as well as a link to a get-up discussion where you can leave thoughts, comments, and questions. Thanks for listening. We hope you enjoyed and have a great day. I am the anti-brace. Um

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