Maybe D was wrong on contracts

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu Aug 20 07:05:29 UTC 2026


On Monday, August 17, 2026 1:23:31 PM Mountain Daylight Time H. S. Teoh via Digitalmars-d wrote:
> On Mon, Aug 17, 2026 at 06:57:04PM +0000, Quirin Schroll via Digitalmars-d wrote:
> > TL;DR: D’s contracts are theoretically unsound, but there’s an easy fix.
> [...]
> > Maybe C++ got something right, or rather, D got something wrong that
> > C++ got right-er:
> >
> > *A virtual function’s postconditions don’t get limit what overriders
> > do when invoked with arguments that don’t satisfy its preconditions.*
> >
> > The violation of this principle might be the reason why D’s contracts
> > never took off.
> [...]
>
> IMO, the reason D's contracts never took off is because they are too
> complex to reason about when mixed with inheritance / polymorphism.
>
> I do use them in my own code, but rarely in class hierarchies, if at
> all.  For simple domain checking of function inputs / verification of
> outputs, they can be pretty convenient for catching refactoring mistakes
> that break existing code.  But mixing them with inheritance leads to
> mind-boggling complexities about who/what can/cannot override
> what/when/how, and what the resulting semantics are "supposed" to be --
> it's just wayyy too much mental effort for marginal benefits.

100%, though I don't think that contracts get used much in D ever without
considering classes.

As far as classes go, even assuming that D's implementation for them is
correct, actually reasoning about them in the face of inheritance is simply
too hard to be worth even considering in the vast majority of cases.
Arguably, if you actually need that level of checks, them maybe you should
rethink your design. And if you're just trying to catch bugs, well, at that
point, you're getting into the issue of whether your checks are even
correct. It's basically the same as writing proofs for code correctness.
Past a certain point of complexity, they're not even vaguely worth it in the
vast majority of cases, because you then not only have to debug and verify
your program, but you have to debug and verify your proof. It's simply not
worth it. Maybe it would make sense for someone like Boeing on NASA, but for
anything approaching a normal program, it's really not.

As for contracts in general (separate from classes and inheritance), D's
current implementation makes them borderline pointless anyway. For them to
be truly valuable, they need to be inserted at the call site based on how
the caller is compiled rather than be compiled into the function itself and
called based on how that function is compiled.

As things stand, for in contracts, you might as well just put the assertions
at the top of the function and not bother with the in contract. And out
contracts are just pretty much useless in general regardless. Occasionally,
they make sense, but in the vast majority of cases, what the result of the
function should be depends on the input, and that doesn't work with out
contracts (at least not with how D implements them). So, for the most part,
unit tests are a far better way to verify what you might theoretically want
to put in an out contract.

The result of all of this is that contracts in D as currently implemented
are pretty pointless. They do have some value with inheritance in the case
where the conditions are simple enough to be reasonable (since you can't
just put the assertions at the top of the function when inheritance is
involved), but that's going to be rare for most folks. And classes are used
pretty sparingly in the average D codebase anyway.

And on top of that, you have the issue of whether assertions or exceptions
are a better solution when it comes to validating function input. There are
plenty of cases where assertions make good sense (and thus where in
contracts could be useful if they were implemented properly), but with
public-facing APIs, there's always the argument that defensive programming
is be a better approach, because then it's impossible for bad input to make
it past the checks at the top of the function instead of relying on the
caller to have done their due dilligence (be it by compiling the code with
contracts enabled or by simply verifying the conditions before calling the
function). And of course, being able to make that decision properly requires
that the programmer properly understand what assertions and exceptions are
for and when it makes sense to use one or the other, and that seems to be
bizarrely hard for some folks to grasp for some reason.

All in all, I think that contracts are a nice idea, but D's implementation
needs some work for them to make sense there. Even then though, I doubt that
I would use them much. I'd use them more than I do now, but I doubt that I'd
use them heavily, and I'd likely still never use them with classes, because
I rarely use classes, and the logic for using contracts with them correctly
is just too complicated.

- Jonathan M Davis






More information about the Digitalmars-d mailing list