Pre-conditions at compile-time with static arguments

bearophile bearophileHUGS at lycos.com
Mon Apr 25 12:44:07 PDT 2011


This is a possible enhancement request for DMD. I am not sure about the consequences of this, so this is currently not in Bugzilla, I look for opinions.

DMD currently runs functions at compile time only if their call is in a context where a compile-time value is expected, to avoid troubles. C++0X uses a keyword to avoid those problems.

[-----------------

Little box:

Time ago I have heard that "enum" is useless and const/immutable suffice. So if "enum" gets removed from D how do you tell apart the desire to run a function (not a global call) at compile time from the desire to run it at run time and assign its result to a run-time constant value?

int bar(int x) {
    return x;
}
void main() {
    enum b1 = bar(10); // runs at compile-time
    const b2 = bar(20); // doesn't run at compile-time    
}

-----------------]

DMD is able to run contracts too at compile-time, as you see in this program (at the r1 enum):


import std.ctype: isdigit;
int foo(string text, int x)
in {
    assert(x >= 0 && x < text.length);
    foreach (c; text[0 .. x])
        assert(isdigit(c));
} body {
    return 0;
}
enum r1 = foo("123xxx", 4); // Error: assert(isdigit(cast(dchar)c)) failed
void main(string[] args) {
    auto r2 = foo(args[2], (cast(int)args.length) - 5);
    auto r3 = foo("123xxx", 4);
}


test.d(3): Error: assert(x > 0) failed
test.d(7): Error: cannot evaluate foo(-1) at compile time
test.d(7): Error: cannot evaluate foo(-1) at compile time


Given that pre-conditions are meant to run fast and to be (nearly) pure, this is my idea: when you call a function with all arguments known at compile time (as at the r3 variable) the compiler runs just the pre-condition of that function at compile-time (and not its body and post-condition).

The advantage is some bugs are caught at compile-time, and the compiler is kept simple (I'd like contracts to be verified statically in more situations, but this requires a more complex compiler). The disadvantage is longer compilation times, and troubles caused by pre-conditions that can't really run at compile-time (like a precondion that uses a compiler intrinsic). A way to solve this last problem is to not raise an error if a pre-condition can't run at compile-time, and just ignore it, and let it later run normally at run-time.

The variable r2 is a situation where not all arguments of foo() are known at compile-time, so here the foo pre-condition is not run.


(Note: the variable r2 is a situation where one argument of foo is known at run-time, and in this case the pre-condition contains a part (assert(x>=0&&x<text.length)) that's able to use this information to catch a bug. This is a possible improvement of the idea is to perform this partial test. This looks less easy to implement, so it's not important).

Bye,
bearophile


More information about the Digitalmars-d mailing list