www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Some pre-conditions at compile-time (reprise)

reply "bearophile" <bearophileHUGS lycos.com> writes:
Some time ago I have suggested the idea of running the 
pre-conditions at compile-time where possible:
http://d.puremagic.com/issues/show_bug.cgi?id=5906

This helps turn some run-time errors in compile-time errors, when 
the inputs are statically known. This is expecially handy for 
literals of user-defined subtypes.

But Walter answered a problem:

 The user must make an explicit choice if code is to be run at 
 compile
 time or run time.
They have just accepted the Ada 2012 standard, that among other things (like the "old" (prestate) for contract programming) introduces a "Static_Predicate" aspect (this page is not very readable): http://www.ada-auth.org/standards/12rm/html/RM-3-2-4.html Static_Predicate allows to attach a compile-time predicate that verifies the validity of a subtype (there is also "Dynamic_Predicate"). So an idea to remove the problem found by Walter is to introduce "static preconditions" in D (there is a "static" before the "in", currently this code is a syntax error): import std.ascii: isDigit; struct Digit { char d; alias this = d; this(in dchar c) static in { assert(isDigit(c)); } body { // Currently this cast is necessary, // despite the pre-condition. d = cast(char)c; } } void main() { // Currently not allowed handy syntax: // Digit[] d = ['5', '6']; // Becomes a compile-time error: Digit[] d = [Digit('5'), Digit('x')]; } Adding "static" to a precondition means the compiler will try to run the precondition at compile-time where possible, and at run-time where it's not possible. (So a "static in" does not mean the pre-condition will always run at compile-time). If you don't add a "static" before "in" the precondition will be run only at run time, as usual. This avoids the unwanted growth of compilation times that Walter wants to avoid. Bye, bearophile
Dec 24 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
In the meantime the gentle Walter has answered my enhancement 
request, explaining it can't work:

http://d.puremagic.com/issues/show_bug.cgi?id=5906

Walter:

 Right now, there's a clear distinction between compile time and 
 run time
 computation. For the canonical example:
 
     assert(0);
 
 We certainly do not want to run that at compile time, because 
 it's only
 supposed to fail if control flow reaches there. For compile 
 time, we've got:
 
     static assert(0);
 
 which only runs at compile time.
 
 From my POV, the "run it at compile time if possible" is fraut 
 with problems.
 There's so much in D that relies on, for example, *failing* to 
 compile an
 expression, that having a wishy-washy construct like the 
 proposal raises a big
 flag of "there be dragons".
 
 I'm strongly opposed to this proposal.
So I have closed that ER down, waiting to open it again if and when there are better ideas. I think I have to explain better what my purposes are. If I write: void main() { byte x = 200; } The compiler refuses that code statically, it means it performs a compile-time test of the value: test.d(2): Error: cannot implicitly convert expression (200) of type int to byte But if I write code like this: void main(string[] args) { byte x = args.length; } It does not perform that test at compile-time, because it can't, the value is known only at run-time. What I'm trying to archive here is a way to emulate that built-in behavour in user-defined types. This means if I define a MyByte type (that is an integral struct value with the same admissible values interval as a signed byte), I'd like a way to define MyByte contracts so this code produces a compile-time error in the first assignment and a run-time error in the second assignment (the y assignment causes a pre-condition violation at run-time): void main(string[] args) { MyByte x = 200; // compile-time error here MyByte y = args.length; // run-time error here } (In theory it's possible to spot a bug at compile time in the second assignment too, but for implementation simplicity I leave that test to run-time.) That's why I have suggested a "static in". But according to Walter answer my solution is not good enough. Other better ideas are welcome. A solution to this problem is going to help D programming, making code stronger. So how is the compiler front-end itself able to perform the range test only on the first assignment here? Isn't the solution used by the compiler generalizable in some way to user-defined types with pre-conditions? void main(string[] args) { byte x = 200; byte y = args.length; } Bye, bearophile
Dec 25 2012
parent Artur Skawina <art.08.09 gmail.com> writes:
On 12/25/12 12:56, bearophile wrote:
 What I'm trying to archive here is a way to emulate that built-in behavour in
user-defined types. This means if I define a MyByte type (that is an integral
struct value with the same admissible values interval as a signed byte), I'd
like a way to define MyByte contracts so this code produces a compile-time
error in the first assignment and a run-time error in the second assignment
(the y assignment causes a pre-condition violation at run-time):
 
 
 void main(string[] args) {
     MyByte x = 200; // compile-time error here
     MyByte y = args.length; // run-time error here
 }
 
 
 (In theory it's possible to spot a bug at compile time in the second
assignment too, but for implementation simplicity I leave that test to
run-time.)
 
 That's why I have suggested a "static in". 
http://forum.dlang.org/thread/kmpcxvrvhjeomitpfnri forum.dlang.org#post-mailman.1091.1344265074.31962.digitalmars-d-learn:40puremagic.com You'd just need an ctor/opAssign overload that would deal with the known-values case. Ditto for other ops. But there are so many other D problems that worrying about things like this doesn't make any sense right now. Also, it's the cases like MyByte x = 100, y = 20; MyByte z = x+y; that need to work (ie have zero RT overhead), and handling them is a little trickier. But likely doable, by using separate "MyByte" types that know their true ranges. Except, then the above syntax won't work anymore, so you'd need additional language changes. Which would be a good idea anyway; but shouldn't be a priority now. artur
Dec 25 2012