On Saturday, 4 November 2017 at 13:59:39 UTC, Jonathan M Davis wrote:
I'm very much of the opinion that proper unit tests pretty much eliminate the need for out contracts.

I think that sqrt example is just bad. Out contracts shouldn't be testing specific values, but rather ranges or nullness or other such things that arguably should be part of the return type, but just don't fit in the type system for whatever reason.

Consider this:

class A {
        A clone()
        out(result) { assert(result !is null); }
        body {
                return new A();
        }
}
class B : A {
        override B clone() {
                return new B();
        }
}

void main() {
        A a = new B();
        A c = a.clone();
}


The `clone` method defined in the base class arguably out to return a NotNull!A, encoding that contract in the type, but we can't really do that with D without breaking the inheritance - where B is statically defined to return B too, since NotNull!B isn't covariant to NotNull!A the way B is covariant to A. (At least not with any techniques I can think of at this time.)

So you can't encode it in the return type... but you can encode it in the out contract for a runtime check.

It also clearly documents that the subclasses must not return null (and can add their own restrictions to further subclasses). One problem I have with some of D's contracts right now is that they are convoluted, ugly code that make for passable internal unit tests, you can't reasonably display as documentation as part of the interface.

But regardless, I say you should not think of out as tests. Think of it as type system extensions.

Reply via email to