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








Artur Skawina <art.08.09 gmail.com>