Improve "Improve Contract Syntax" DIP 1009

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Nov 3 02:32:41 UTC 2017


On Friday, November 03, 2017 02:08:43 codephantom via Digitalmars-d wrote:
> On Thursday, 2 November 2017 at 18:40:26 UTC, bauss wrote:
> > I disagree with that, because it would make the language very
> > verbose.
>
> Personally, I think function headers are starting to become to
> verbose.
>
> I don't believe removing the separate scaffolding that
> accompanies contracts, so that you incorporate contracts directly
> into the scaffolding of a function header is a good design choice.
>
> There was an inital design choice to put in that scaffolding for
> contracts, and presumably it was done so for a reason. I didn't
> see that discussed in the DIP.

They're designed so that you can run more or less arbitrary code, and for
that having normal blocks like in, out, and invariant currently do makes a
lot of sense. The issue is that if you just need something short -
especially if you're just asserting some conditions and not running any
other code to set up the assertions - then they get awfully verbose for what
they're doing. So, having a terser syntax for simpler contracts is
desirable.

Personally, I hate how verbose they are, but my solution is just not to use
them. And IMHO, the only place that they add real value is in classes, where
their success or failure can be &&ed or ||ed based on how that should work
with inheritance. For struct member functions or free functions, where no
inheritance is involved, they add considerably less value.

in contracts for functions that aren't members of classes can just be done
at the beginning of the function, and you don't lose anything. If some
aspect of the contracts were checked at compile time, or if whether
contracts were run or not depended on how the caller was compiled rather
than the callee, then having an explicit in contract could be useful. But as
it stands, they really don't add anything over simply asserting at the
beginning of the function (except in the case where inheritance is
involved).

out contracts IMHO are almost universally useless for pretty much the same
reason that unittest blocks that are compiled into templates are almost
universally useless: they have to be so generic that in most cases, you
can't do much with them. It almost always works far better to test the
result of functions by using unit tests to test that known inputs give the
correct results. Pretty much the only case where out contracts work well is
when you have a very specific, testable condition that all results must have
and which does not depend on the input, and most functions simply don't work
that way.

And while invariants are of some value for classes, IMHO, they should be
avoided like the plague in structs. The problem is that _every_ public
function (including opAssign) has the invariant called before and after.
That means if you ever try and do anything with void initialization for
performance, you're screwed if you have an invariant, because whatever
garbage is in the member variables will be tested as soon as you try to
assign a valid value to the object. If it just tested _after_ opAssign, then
that would be fine, but it tests before as well. And it may actually be that
if emplace is involved (e.g. with an allocator) that initializing a class
with an invariant could have the same problem. So, much as I think that
invariants could add real value (certainly, they're far less verbose than
manually adding those same checks to ever public member function), I never
use them.

So, while I really don't like how verbose contracts in D are, and I wouldn't
mine a more concise syntax, I also find it hard to care, because I'm not
going to use them either way.

- Jonathan M Davis



More information about the Digitalmars-d mailing list