Suggested Change to Contract Syntax

FatalCatharsis via Digitalmars-d digitalmars-d at puremagic.com
Thu Mar 10 13:07:09 PST 2016


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?


More information about the Digitalmars-d mailing list