Invariant and pre/post-conditions order

bearophile bearophileHUGS at lycos.com
Thu Jan 19 14:29:28 PST 2012


Walter has recently closed a bug report without fixing it and without an answer, it's about contract based programming:
http://d.puremagic.com/issues/show_bug.cgi?id=5024

So I'm asking for more info here.

As reference I use this little program (I have improved it a bit compared to the one inside issue 5024):



import std.c.stdio: printf;

class Foo {
    int x = 0;

    invariant() {
        printf("Foo invariant: x=%d\n", x);
        assert(x >= 0);
    }

    this() {
        printf("Foo constructor: x=%d\n", x);
        x = 1;
    }

    void setX(int newx)
        in {
            printf("Foo.setX precondition: newx=%d\n", newx);
            assert(newx >= 0);
        } out {
            printf("Foo.setX postcondition: x=%d\n", x);
            assert(x == newx);
        } body {
            printf("Foo.setX body\n");
            x = newx;
        }
}

void main() {
    auto c = new Foo();
    c.setX(10);
}



Currently it prints this, that I don't like:


Foo constructor: x=0
Foo invariant: x=1
Foo.setX precondition: newx=10
Foo invariant: x=1
Foo.setX body
Foo invariant: x=10
Foo.setX postcondition: x=10



I'd like this order:

Foo constructor: x=0
Foo invariant: x=1
Foo invariant: x=1
Foo.setX precondition: newx=10
Foo.setX body
Foo.setX postcondition: x=10
Foo invariant: x=10


An example of why I think that's better. This is the same program with a bug:


import std.c.stdio: printf;

class Foo {
    int x = 0;

    invariant() {
        printf("Foo invariant: x=%d\n", x);
        assert(x >= 0); // line 8
    }

    this() {
        printf("Foo constructor: x=%d\n", x);
        x = 1;
    }

    void setX(int newx)
        in {
            printf("Foo.setX precondition: newx=%d\n", newx);
            assert(newx >= 0);
        } out {
            printf("Foo.setX postcondition: x=%d\n", x);
            assert(x == newx); // line 22
        } body {
            printf("Foo.setX body\n");
            x = -newx;
        }
}

void main() {
    auto c = new Foo();
    c.setX(10);
}


If I run it it gives:
core.exception.AssertError at test2(8): Assertion failure


So the bug is caught by a the generic invariant at line 8 instead of what I think is the correct place, the setX post-condition at line 22. The post-condition is a test meant to verify that the setX() body is correct, while the invariant contains more general tests. So I think it's more right to run the specific tests first, and the more general later.

If I am mistaken please I'd like to know why the current design is better (or maybe why it's just equally good).
Thank you :-)
Bye,
bearophile


More information about the Digitalmars-d mailing list