A nice blog post about assertions, preconditions, invariants and
their usage:
http://blog.regehr.org/archives/1091
It shows how D avoids some troubles, and offers most of what's
needed.
The checkRep() Idiom
It could go in the D invariant. I use it often.
The second way to accidentally change the state of the
program is like this:
assert (treeDepth() == 7);
but unfortunately treeDepth() changes the value in some
variable or heap cell, perhaps via a longish call chain.
In case it isn't totally clear, the problem with side-effects
in assertions is that we'll test our program for a while,
decide it's good, and do a release build with assertions turned
off and of course suddenly it doesn't work. Or, it might be the
release version that works but our debug build is broken by a
side-effecting assertion. Dealing with these problems is highly
demoralizing since assertions are supposed
to save time, not eat it up. I feel certain that there are
static analyzers that warn about this kind of thing. In fact,
the original paper about the work that became Coverity's tool
mentions exactly this analysis in Section 4.1, and also gives
plenty of examples of this bug. This is an area where language
support for controlling side effects would be useful. Such
support is extremely primitive in C/C++.
On this topic I have recently added an Enhancement Request, to
disallow side effects in assert():
https://d.puremagic.com/issues/show_bug.cgi?id=12028
Two simple examples of code that is meant to be forbidden:
int foo(ref int y) pure nothrow {
return y++;
}
void main() {
int x;
assert(++x);
assert(foo(x));
}
Bye,
bearophile