Don:

>"out" contracts seem to be almost useless, unless you have a theorem prover. 
>The reason is, that they test nothing apart from the function they are 
>attached to, and it's much better to do that with unittesting.<

I see three different situations where postconditions are useful in D:

1) Sometimes the result of your function/method must satisfy some simple 
condition to be correct.

As example, it must be a nonnegative number. Then you add assert(result >= 0, 
"..."); in the out. For a Phobos example, std.algorithm.countUntil 
postcondition is allowed to test assert(result >= -1, "...");

Other possible conditions are the output string can't be longer than a certain 
amount (like longer than the input string), and so on.

In certain cases the program the finds the solution is slow, but testing the 
correctness of a function is fast.   I have hit many situations like this. 
As an example you test if the result of a complex sorting algorithm is ordered, 
and with the same length of the input (but maybe you don't test for the output 
items to be the same of the input).


2) I have found many situations where I am able to solve a problem with both a 
simple and slow brute force solver, and a complex and fast algorithm to solve a 
problem. The little program maybe is too much slow for normal usage, but it's 
just few lines long (especially if I use lot of std.algorithm stuff) but it's 
much less likely to contain bugs.
You can't always verify the result of the fast algorithm with the slow 
algorithm, this is not useful.
In such situations I write the postcondition like this:

in {
    // ...
} 
out(result) {
    // some fast postconditon tests here
 
    debug {
        assert(result == slowAlgorithm(input));
    }
body {
    // fast algorithm here
}


This way, in release mode it tests nothing, in nonrelease build it tests the 
fast postconditions, and in debug mode it also verifies the fast algorithm 
gives the same results as the slow algorithm. Generally solving a problem in 
two quite different ways helps catch problems in the algorithms.


3) When D will get the prestate ("old" in some contract programming 
implementations), I will be able to use the prestate inside the postcondition 
to verify better than the function/method has changed the globals, or instance 
attributes in a correct way. You can't put such tests in the class/struct 
invariant, or in the precondition.


I'm using postconditions often in my code (less often than preconditions, but 
often enough). A theorem prover is not strictly necessary for them to be useful.

Bye,
bearophile

Reply via email to