I am very new to D so I apologize if I'm very uninformed. I'm learning D by porting a big (awful) c++ project to D so that I may take advantage of all the lovely testing and QA features. I am currently moving a class over that I have which represents a 2 float vector and I've run into a problem with contracts. Here is a short excerpt:

struct Vector2(T) {
    T x = 0;
    T y = 0;

    Vector2!T opBinary(string op)(const ref Vector2!T rhs)
        if(op == "+" || op == "-" || op == "*" || op == "/")
    in {
        T prevx = this.x;
        T prevy = this.y;
    }
    out {
        static if(isFloatingPoint!T) {
assert(mixin("approxEqual(this.x, prevx"~op~"rhs.x)")); assert(mixin("approxEqual(this.y, prevy"~op~"rhs.y)"));
        } else {
            assert(mixin("this.x == (prevx"~op~"rhs.x)"));
            assert(mixin("this.y == (prevy"~op~"rhs.y)"));
        }
    }
    body {
        Vector2!T ret;
        mixin("ret.x = this.x"~op~"rhs.x;");
        mixin("ret.y = this.y"~op~"rhs.y;");
        return ret;
    }
}

this example obviously does not compile. What I am attempting to do is store the initial value of the x and y before the body is run, so that I can use those values in the post condition. I've read around and asked a question on stackoverflow, and it seems that there is no facility for this.

I am NOT very knowledgable in compilation, but I do get the gist of it. I was hoping to suggest a syntax change and get some opinions on it. What if contracts were done like this:

struct Vector2(T) {
    T x = 0;
    T y = 0;

    Vector2!T opBinary(string op)(const ref Vector2!T rhs)
        if(op == "+" || op == "-" || op == "*" || op == "/")
    contract {
        T prevx;
        T prevy;

        in {
            prevx = this.x;
            prevy = this.y;
        }
        out {
            static if(isFloatingPoint!T) {
assert(mixin("approxEqual(this.x, prevx"~op~"rhs.x)")); assert(mixin("approxEqual(this.y, prevy"~op~"rhs.y)"));
            } else {
                assert(mixin("this.x == (prevx"~op~"rhs.x)"));
                assert(mixin("this.y == (prevy"~op~"rhs.y)"));
            }
        }
    }
    body {
        Vector2!T ret;
        mixin("ret.x = this.x"~op~"rhs.x;");
        mixin("ret.y = this.y"~op~"rhs.y;");
        return ret;
    }
}

In this example, the contract would represent a function that is invoked on each invocation of the function. in and out would enclose the values prevx and prevy. in would be invoked immediately after, followed by the body, and then followed by out.

Syntactically I think this is clear, but I don't know much about the technical implementation. Is this feasible?

Reply via email to