Invariant contracts in D are runtime checks that automatically verify conditions before and after member function execution, including constructors and destructors. For structs, invariants are straightforward to implement and enforce. For classes, invariants are inherited by derived classes, but when overridden functions are called, the base class invariants may not trigger as expected, requiring developers to use private helper functions to ensure proper enforcement across the inheritance hierarchy.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
invariant (contract programming) classes/structs (classes part 6 of N) [Dlang Episode 144]Added:
Hey, what's going on folks? It's Mike here and welcome back to my deep programming language series. In today's episode, we're going to be talking about invariants. And invariants are a feature that supports contractbased programming in the deep programming language. Now, let's go ahead and dive into this and talk a little bit about contracts here.
So, I'm going to go ahead to documentation here and we can find the uh contract programming here in the list or you can otherwise find the particular topic we're going to be talking about today in variant with classes or strrus.
that this collects everything nicely in one page. Now, what is contract programming if you've never seen this or maybe you've seen this? In fact, if you've been watching this series, we've learned about things like asserts for instance, which are a sort of contract that must be true. In fact, so true that if that assertion is not, whether it's a static assert or a regular assert, the program should crash, right? Or not compile, right? That's how important it is. That's a contract of legality, let's say, of like what it means to be a functioning correct program. So to support this, we have contract programming. And the particular feature we'll be talking about today is invariant, which you'll see is bullet number three uh on this list. But anyways, let's go through this page here. Uh so contracts enable specifying conditions that must hold true when the flow of runtime execution reaches the contract. uh and again as I mentioned static assert indeed would be at compile time when we are compiling or evaluating something uh at compile time uh if a contract otherwise is not true then the program is assumed to have encountered an undefined state thus usually we crash okay so that's usually the idea here okay uh the rationale building contract uh support into the language provides a consistent look and feel for the contracts tool support the implementation can generate better code using information gathered from the contracts easier management enforcement of contracts and handling of contract inheritance. Okay, so we're going to talk about this because we're going to be talking about both strrus and classes today. Uh and then we could see uh D here bouncing off the bug here because contracts are again a tool for helping us be more resilient or write better and more correct software. All right, so we've already talked about assertions in this series. Uh, and I'm going to revisit pre and postcontracts later on here, but since we've been talking about classes and um strrus previously, I think this is the place to start. Uh, you could go ahead and check out some of the other references here that uh might be useful, but let's go ahead and open up the strruct and the class page here just so we can get a flavor of this.
Now, before I dive into strrus here, I just want to talk about um this sort of section. Um, this, you know, was also uh covered in Ali Charlie's book. Um, this is one of the reasons I got into programming the DP programming language having contracts. I think it's just a really really nice forwardlooking feature at the time. Now other languages like C++ are getting this. Um, I've used other languages um have had contracts and sort of uh educational scenarios.
Some of you uh on this channel watching have used languages like ADA [laughter] for instance which are known for sort of their uh contracts. Um and again there are many different uh versions of of contracts here but again it's a really cool and important part of specifying what is correct behavior. So you know having tools to do this is really really important. So again it's a reason I think D is a great language for doing actual software engineering it. All right so with that said anyways let's go ahead and dive into the strct invariance which is our first form of contracts here. Uh you can see basically the syntax is this keyword invariant. Um and then we can have uh basically a block here. Um so let's go ahead and look at um that here. Uh let me see if there's anything else I want to talk about.
Yeah, I think we're just going to do the uh block here. Um so basically what this is is we have this invariant block here and we can have as many of these as we want and they'll be defined in the sort of order or execute rather in the order uh that they're defined in. And we can kind of pile in all of our assertions here. And basically what this invariant does is uh before any of our member functions uh including our special member functions, things like constructors, destructors, it'll check these conditions. And then it'll also check these conditions also hold true after the function. Okay. So let me just go ahead and highlight this. And by highlight this, what I mean is draw exactly what I mean here. So let's say we have a strruct or a class here. I'm going to have my invariant.
Okay, let's just define one of them here. And I'll have some assert statement. You know that'll do something. And then uh let's say I define some other member function here.
FU give it a no return type here. You can basically take this block here and put it at the very start and the very end here. Okay, that's effectively what's going to be going on here. Okay.
Uh, each of these invariant blocks must hold true. So, we want to check the state before the function and the state at the end of the function here. Okay.
That's the idea. Simple as that. Okay.
Um, [clears throat] okay. So, we can go ahead and see with this example here where maybe we have a date here and users can specify dates maybe with a day and an hour. Uh, and of course, uh, well, this depends on what calendar you're using, of course. Um, but you know, uh, the calendar that I'm using has days from 1 to 31. So for representing these with an integer, we want those that to be the representation. And same for hours, 0 to 23 or depending on the type of representation of time, maybe 0 to 12 uh or 1 to 12, let's say, uh 12-hour clock.
Um but anyways, uh so this these invariants sort of make sense. Hopefully this makes sense to have this assertion that yeah day never exceeds uh the value 31 or goes under uh one and hour never goes under zero and 24-hour clock or exceeds 24. Okay. So we can always check those operations. Okay. Uh and again here is the state. So typically uh invariants operate on the stuff that mutates. That's your member variables.
And you can check those conditions. So rather than littering every single function here with a a search here, you can just put in the invariant. Okay. So let's go ahead and uh let's go ahead and work with this is actually a nice uh example. I like this date time example here. Uh let me scroll down to the uh invariant section here. There we are.
Structure.
Um and let's go ahead and do something like this. Um now you know again just because maybe we want to change things up just a little bit here. Let's go ahead and um say we have some account system here. Let's create a strct for a uh person. Let's just do for a generic person here. Uh and you want to store again these things here. Now you can have your day um uh let's sort of store their like date of birth. So you have like their day uh the year uh and the month here. Okay. Uh, a couple different ways that we could do this, too. Uh, D also has bit fields. Um, so maybe we would only need like five bits, two of the five, right? Uh, for the days. Um, but again, let's just assume that we're going to use an integer here. Even if we're being pretty good here, we could even use a like a short or a ubite or something like that. But again, let's just work with inch for now. Uh, you could compact this as you want here. So, anyways, let's have our constructor here for our person. And that we want to know their uh date of their birth, the month and the year.
And we can assign these uh month equals m and okay there we are. So we assign everything here and then let's go ahead and recreate this. Let's have our invariant and then our assertion statement here.
So let's assert day is greater than zero.
Day must be greater than zero. And I'm going to do this just a little bit more simply here. Uh let's say the same for month. Uh in year let's say nobody was born before 1880. Um so you know something like that here. We probably don't have any 46 year olds uh in the world. Uh and if you are watching this channel in 156, make sure you uh leave us a comment below, [laughter] you're a Guinness World Record holder uh for the years you were born. So anyways, uh this is the idea here. And then maybe we can have something like a function here uh for this person where I don't know they want to like enter our website or something uh and we should validate them uh this way or more likely probably what we're doing here is like registering this user uh you know some functions some functions for registering them here or you know most likely probably what we want to do here because a search might not actually be the right tool for doing something at runtime. We might actually like throw an exception or something. Um maybe we want to just call this like parse user data or something. Uh or validate user data, you know, something like this. Something of this um thing here. And uh okay, let's go ahead and see how this works here. Let's see if we can trigger the invariant here. Okay.
And I'm going to go ahead and just compress this just a little bit here.
Um, I really got to make this the default here. I have it on for other reasons.
Uh, oops. Let's see here. Set fold method.
Get that to work here. Oh, not indent.
Let's do manual.
Manual. There we go. All right. So, let's hide a few of those things here just so you can see everything on the screen.
Uh, all right. Anyways, uh, so let's go ahead and create our person P. Uh, and let's see here. Let's just run this with RDMD here for now.
This seems to be so far so good. We're running. Uh, but we haven't really done anything here.
And in fact, uh, when we just create the strruct here and we just take in the initial values, uh, which I could go ahead and show here, right? these are all zero. Um that that was okay, right?
So this didn't trigger the invariant here. So that brings up this point here of you know again I I showed you where the invariant gets used at the start and the end of these functions here. But if I'm just initializing a strct, it's that's not going to cause any problems.
So we can see these rules down here of when the uh strct invariant um will be called. So okay, a few things. As I mentioned, you can have multiple invariant blocks here if that helps you organize things. They'll be applied in lexographical order. Uh let's see here.
They must hold at the end of the uh constructor. Um so that would be um uh so not necessarily at the beginning because you're constructing the object.
So that's one uh note about the special member functions that sort of makes sense here. Um and then otherwise at the end entry and exit of all public or exported non-static uh member functions.
Okay. Um, that kind of makes sense to I mean, so does this apply to like the private ones? Uh, well, I mean, I guess this is your your interface here, the public ones here. So, we could actually test that out. That's kind of interesting to think about. Um, all right. Um, like like should it also hold against the private ones? Uh, that's something you could kind of debate here.
But public is what you're going to be calling out to. Private might be stepping up things in multiple stages.
Uh, setting up things, excuse me, in multiple stages. Um, okay. Um, what else do we want to say here? I think that's pretty much it here. Yeah, let's go ahead and now give this a try. So, let's go ahead and initialize our person here.
This time with the constructor. So, let's say their date of birth it' be the first day of the first month, which is January um in 19 uh 50. Something like that. Here, let's run this. That's okay.
Uh let's see what if there what if I put in zero here. Whoops. Okay, so we caught that. Okay, so this could be a little bit of a lifesaver here. Uh when we're just, you know, doing our testing here to say, hey, we've entered, you know, we've already constructed this object sort of illegally. Day must be greater than zero. Okay, now we get these question marks and we want to know where or you know why the invariant was triggered. So, uh remember compile with debug information here. Okay, and that'll give us some line numbers. So let's clear that up here just so we can see a little bit better. Uh so day must be greater than zero. You can see that was triggered at line 14. Okay, that's where our invariant was. And we just got to go backwards in the stack trace to say hey uh let's see I was constructing in main uh here and then the main person invariant um for this strct was called and ultimately ultimately if I go back here uh let's see it was in the constructor at line seven. So in this uh function when I was trying to build this and where did I start? Well from person here. Okay. So I can kind of trace backwards using the stack trace here. Uh you can see the invariants um you know are sort of named these like special functions. I wouldn't call these directly um [laughter] uh and I think they're sort of numbered in this way to get like zero one etc. Um uh anyways that so that's a note there.
Uh the other not thing to note here about invariance is um I shouldn't do stuff like this day equals 7 here. In fact, I don't think I can because uh this is a const function as we're getting in the error message here. Okay, so just a note there. So you know keep your invariants simple. Keep them probably to just lists of asserts. Uh that's what I tend to do here. And I think there are some notes here on uh best practices u or some you know thoughts on what to do here. Uh yeah let's see cannot call yeah you can't call public member functions from the invariant because that's going to cause more mutation and also from this public member function that's going to cause um well the another invariant to be triggered right so we're going to get end up in this like recursive loop here. So that probably makes sense again why we can um call into uh in our invariant uh private, right? We only want to check the invariant on public functions. Okay, that that sort of settles that debate.
That makes enough sense for me. All right, so anyways, um that's kind of uh the basics here. Now, um you might have caught me do this a little bit and you said, okay, uh you know, okay, so we've triggered our invariant, but what about performance, Mike? What about performance? How do we turn these off here? Well, uh let's go ahead into uh the deep programming language website here. Let's go to the compiler flags here or the command line reference here.
Uh and the first one I'm going to show you is release. Um let's go ahead and show you that flag here. Uh compile release version, which means not emitting runtime checks for contracts and asserts. Okay, array bounds checkings. Uh, okay. So, it does some other things, but the the main thing here I want to focus on is release is one way to turn these off. Okay. So, I can do release and you know my uh invariant won't be triggered. Okay. Uh because I won't be checking them, right?
The the assertions are basically off.
The invariant is off. Um so simple as that here. Uh now if you want to be very uh have a little bit more specific control over this, you can do with check here.
Um, and this is will sort of give you some more behavior on turning on and off specific flags here. Um, and then the action is these things in the bold. Uh, and then you can set them to on off. Um, or there's this uh like safe only mode for like safe functions only where you use this. Um, so let's just go ahead and show you how that works. Uh, let's do check uh invariant. Let me make sure I spell this carefully.
uh off and again that will turn things off.
Okay. So you can totally do that. That is totally fine here. Okay.
All right. Um but we know our program is not fine. It is crashing. Um so let's go ahead and make it crash some more. Uh let's fix this. Let's go ahead and update. Uh so we're valid here. And let's say we do something here. Again, we're parsing in user data and actually, you know, maybe populating these strcts from like a CSV file or something. Uh and let's say we have a empty or a null field or something that's indicated by negative one here. Uh so if I just have that that's okay. Uh but as soon as I call into it, uh let's go ahead and see is our invariant again triggered. It is okay. Right. And we're able to again trace back here from our main at line 27. Uh and then we'll look at our invariant uh this block here.
Um well I guess there's only one for us to look at but again just kind of working backwards through the stack trace you can figure out uh where that was triggered from. Okay so I think we get the idea of invariant. We know how to turn them on and off. Now let's go ahead and look at classes to continue our discussion there. Uh and class invariance here. So section uh 16.9 let's go ahead and take a look at that here. Invariant. Uh so class invariance pretty much the same thing we just showed you with strrus here. Um but uh what gets a little bit more interesting is you know if I define an invariant for like person does it get carried down to the drive classes? Okay. So let's go ahead and uh what I'm going to go ahead and do here is let's just comment out this for now just so you have it uh for your own records.
And let's go ahead and we'll just yank this and make a copy here.
And let's hide this guy. And let's now make this a class. Simple as that. Uh, do we need to do anything else here?
Let's see here. Oh, we need to do new.
And let's see here. All right, great.
Okay, so we're back to square one. Uh, we've just translated this into a class by changing the keyword and then making sure that we allocate things on the heap here. Um, and the invariant is otherwise triggered as expected, right? We're parsing our user data here um and uh carrying that on here. Okay. So now let's go ahead and say for our class here uh let's go ahead and derive um something else here. I'm going to go ahead and hide that implementation here.
Let's let's create a student who is a type of person.
Uh and let's go ahead and override this functionality. I'm going to parse the user data. Override override there we are and then maybe within this function we do something like set their day equal to negative one for whatever reason okay now let's make sure that we uh instantiate this as a student here so it'll be treated like a student and call the students overridden uh function here and my question to you is do you think this invariant is going to be uh triggered here right it's a different class I can't see the uh invariant here uh so to speak. But will it be triggered? And the answer is uh oh, let's see here. Uh at line 46, we got to define our constructor.
Uh let's see here. Yes. Uh let's use this one here.
Um like this. And um actually, let me show you this because I showed you this in the last video as super uh we could just do this, right? We'll just forward those arguments here to our uh superass which is person. Okay, now it's a little bit of a hint to the original question that I was asking was is this invariant going to be triggered? Uh you know we're using this you know superass here. Uh but but let's see what happens here.
Whoops. Uh so we call on our person new student. Uh I did W again. And I don't know why I did that. Uh, and it didn't get called. Hm. So, this is a little bit curious here because um, you know, if I'm reading the documentation, my assumption might be uh, let's go and go uh, oops.
There we are. Back to our class invariance. Um, it said something about let's see if I have my ah here it is.
Any any class invariant for a base classes are applied before the class invariants uh, in the drive class. Okay, so that's so right there. So what what is my expectation then for having this invariant here? Um does that get like copied down and applied to this base classes member function? Well, that that kind of wouldn't be fair. I mean it would be fair if I had another function up here. Let's go ahead and say um let's just call this foo here. And let's do the day equals7.
Let's let's trigger it with month here.
something like that. Some illegal behavior here. Um, and then a person here I can call fu. So let's see here.
Is this going to this is going to crash here, right? I mean because I'm still enforcing this invariant here on on fu.
Okay, so that makes sense, right? I can see this invariant within the same uh code block even though my type here for p is a uh type of student here. But again, I'm I'm up, you know, calling my base class or my super classes member function here. Okay. Uh so hope hopefully that makes sense that this invariant is getting enforced here. Uh but let's let's hide that or push that aside for a moment here.
And again try to understand why this overridden behavior here isn't catching the invariant. That's well I mean we can kind of think of this as it's within the scope of person uh here. Okay. So that's when it should be called here. But I mean let's let's try to see um where this is being called here or how many times I can put a little right line here. Invariant is called something like that. Um so [clears throat] it is being called uh and where is it being called here? Well, it's got to be called at the start and the end of our member function. So let's try to let's try to indent this and get to the bottom of this here. Uh let's go ahead and see here. Let's put a right line for you know student constructor uh and student constructor end.
Okay. So let's see here. So the student constructor uh starts uh and then the invariant called at least once. And then when the constructor is ending, uh, we see the invariant is called at least two more times here. Okay, so this is kind of interesting here. Um, and let's go ahead and hide some more of these so we can see what's going on here. Um, well, where would it be called in between here? I mean we've got our constructor for person person start and person end.
Okay. So this gives us a rough idea. I mean it's a little bit hard because the invariants being called after here but um so again if we just try to trace this here where we've got our uh persons here it's a little bit hard to trace. Let's try to remember our rules here. So at the um end of student here uh the call into super that brings us up to here person and then by the time we get to the end of our constructor right that's the first time the invariant's going to get called. Uh it's going to get called again at the end of our uh student here.
Um, and then it looks like it looks like it is being called uh the invariant perhaps with our parse user data, but it looks like it's maybe operating or not testing uh properly here. I would have expected this to fail here. Now, if I instantiate this as student here, um, that seems to be okay, too. But I could I could still put in some sort of fail here.
Uh let's try this one here.
P do fail. Let's just call this one here. Um and then now we're getting the uh assertion error here. Okay. Atline uh 40 uh or it's triggering this invariant here. So I think this is just one of those sort of compromises in the language here. And this is what I want you to sort of understand here. Um it's you know the invariant clearly we can see that the invariant did get uh inherited here right because when I call this fail function here on something that I specifically said you know the static uh type here is going to be student we create the new student and then we call this uh member function because it's defined within student there uh that inherited the invariant.
Okay. Um, so hopefully that that makes sense here, but it was a little bit weird in the case where we overrode the function and called it and it looked like the invariant was called when we printed it out here that it didn't trigger here. That's something I'm a little bit weary of. Now, why is this a little bit weary? Well, the way to think about this too is is it fair if I have um this sort of uh type here for the derived type student um for us to basically have an invariant that covers all the overridden uh uh member functions here because you know we're kind of saying override that behavior do something different. So, so where exactly does it fail is kind of an interesting question here. Now, I would sort of argue that it probably should affect all of these, but we've got a better tool for that actually. Um, and that goes back to the contract programming, uh, which I think I'm going to do in a separate video because this one's already gotten long here. Um, and that is having these pre and post, uh, contracts or these in and out here. So, you're welcome to go ahead and take a look at these. Uh, but I think those will be a little bit uh, easier to use.
So, let me kind of wrap this up by saying um if you're going to use classes with invariance and um another little thing that you can do here is you could also another way to do this let me actually play around with this idea for a moment here is just say the um let's just write as a interface uh and call it contract and what if I put the invariant uh in here okay something like this here. Um, okay. Let's see here. Uh, okay. So, I've got my uh invariant block. Okay, I can't really do this, right? The compiler is telling me, hey, I can't because you can't have executable code within the interface, right? That's that's the wrong tool for this. So, um, so again, that's sort of make concrete what interface is. But again, we do have a tool we could reach for on specific functions with in andout contracts here.
Okay. Uh this would actually be kind of nice to have some sort of like specification. I mean you can just inherit um you know some other class or something like an abstract class maybe uh with this invariant uh block and try something like that. But anyways that that was the just a little experient experiment uh to remind us what we can and cannot do with interfaces.
Um okay so again let me try to wrap this up a little bit more cleanly here.
probably where I like invariance I mean this is the most easy use case here is within strrus right we don't have to worry about the inheritance rules uh whether it is or is it going to get executed how many times and so on so invariant kind of just works nice for enforcing these conditions it's super super useful um when you are debugging or in development mode right then you could just use the release flag and so on to actually um turn these on and off or the check actions um flags that we showed before uh works pretty nice. And again, invariants are available when we do class-based inheritance, but they're just a little bit trickier to follow as we we tried to kind of follow it and see here, but it seems like it didn't or did apply in some cases with the overridden function. And again, I was just trying to help us reason through why it might not be fair for us to have the same inferient on executing on the overridden member function. Um maybe this is something that gets implemented. Maybe this is even a um I don't know if it uh specified or if this is implementation defined um for what the actual behavior should be because I would have expected this to fail uh based off my invariant.
Um, but this also uh begs us to the question of could I have just, you know, done something like this and just said, well, uh, let's just write a private function called my invariant, right?
There's always a way to get around this stuff. My invariant.
Uh, just pop this in here. Uh, this will be a void function here. We'll just call my invariant.
Uh, I could do something like that here.
Let's see what else do I need to do here. Uh I think this needs to be uh what does it need to be like const or something?
Yep, something like that. Uh and then I can basically just pop in here my invariant block here.
Uh and let's see here. Did I get another? Oh, it's calling fail still.
Let's get rid of fail here. Now it in fact is uh catching this. Um, it wasn't before, right? When I didn't have this block here, right? It was okay. So again, maybe that makes things that makes things a little bit more clear for me. So I don't know if that's an implementation defined thing, but maybe this is the right way to use classes with inheritance. I'm actually curious if folks use this particular feature. I use them with strrus. I think they're pretty cool. I think they are handy here for classes and should be allowed, but um it looks like we need a little bit more care to get the um uh inheritance to work. Uh I also sort of like in some ways putting this with a named function because then I can, you know, put a break point on it or something [laughter] and see every time that it's being triggered. Uh right. So we'd expect to be seeing this twice at the entry and exits a functions. It'll make the call stacks a little bit easier to to read if I could just see my invariant. um here. I mean, it adds uh certainly some overhead, but um yeah, we're we're using this in debug mode.
Anyways, so anyways, okay, I'm happier where we landed here uh by just being able to have this maybe sort of strategy uh and clean things up a little bit. So, anyways, folks, that's why you got to watch till the end of the videos here.
And if you've made it here, let me know what you think about this strategy here.
I think I'm quite happy with this because this gives me ultimately control then over if I want to enforce everything that it means for the type person here onto a student right and that's really the discussion here to say well what should the invariant be because now this is a specialized type right student I mean it is a type of person but uh have the invariance changed can students live to be more than 140 years old for instance um yeah probably [laughter] so anyways I'll go ahead and leave it there folks hopefully enjoyed this lesson. Sorry, it went a little bit longer here, but we had to do a little bit of exploration there. As always, feel free to check out the community here, of course, msh.io, you know the deal here. Uh, but thanks anyways for your time and attention. Again, let me know if you made it through the end of this video because it was a long one, but uh hopefully fun and you got to learn a little bit about contracts. All right, with that said, I'll look forward to seeing you in the next one.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











