digitalmars.D - Some pre-conditions at compile-time (reprise)
- bearophile (46/49) Dec 24 2012 Some time ago I have suggested the idea of running the
- bearophile (50/74) Dec 25 2012 In the meantime the gentle Walter has answered my enhancement
- Artur Skawina (12/24) Dec 25 2012 http://forum.dlang.org/thread/kmpcxvrvhjeomitpfnri@forum.dlang.org#post-...
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
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
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