www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - C, D, undefined behavours, ++ -- operators

reply bearophile <bearophileHUGS lycos.com> writes:
This Reddit thread:

Has let me find this curious pack of slides about C and C++:

While reading those slides I was glad that D avoids me several of those ugly
problems (not all of them, because variable definitions are allowed with =void
in D, but they are uncommon).

This is the cute page 194 of the slides:

What do these code snippets print?

 int a=41; a++; printf("%d\n", a);           42

 int a=41; a++ & printf("%d\n", a);         Undefined

 int a=41; a++ && printf("%d\n", a);         42

 int a=41; if (a++ < 42) printf("%d\n", a);  42

 int a=41; a = a++; printf("%d\n", a);      Undefined


Regarding a line of C code like:

a = b() + c();

Negitivefrags from Reddit says:

The order is undefined so that the optimiser can do it's work. It is quite
possible that after inlining doing C first and B after is faster than the other
way around.<

In my not so humble opinion on modern computers this is acceptable only in a language able to enforce the purity of the b and c functions (maybe it was acceptable on 1970 year computers). D has purity, so I really hope D will throw in the trash can most of this crazy C stuff about undefined behaviours :-) If something compiles, it has to give a deterministic output on all compilers, otherwise it has to become a compile-time error. Walter has expressed several times his desire to turn this code to defined in D: a++ & printf("%d\n", a); a = b() + c(); (But D will be free to run b and c in its preferred order if both b and c functions are strongly pure.) Turning that code into defined behaviour, shared by all future D compilers, will be a large improvement for D. The little performance loss is nothing compared to having code that gives the correct result. I firmly believe that speed is _nothing_ if the code gives the wrong answers. The alternative acceptable solution is to statically forbid as many things as possible that will produce undefined behaviour at run time (but probably you can't remove all of those behaviours from D code). In real C code that I have to digest and debug I find every day lines almost like this one (a bit simpler than this): z = w[x] = a[x + ++b[y + ++j]]++; Turning this C code into defined behaviour in D will be an significant improvement, but maybe it's not enough. A part of me desires a language (something like D, let's call it D-like) that statically forbids shitty code like that because for me it is almost impossible to understand (maybe it's just a limit of my brain, who knows). This is why I think turning that code into defined D behaviour is not enough for me... :-( I usually laboriously and slowly unpack a line of C like that, running tests every little refactoring step, to turn it into several lines that are a bit more sane and understandable for me. To avoid many of those troubles it is enough to change the semantics of the pre/post increment/decrement operators, to let them return only void. This small change is able to avoid several troubles of C code. Python doesn't have the ++ -- operators, this was a wonderful design decision. Unfortunately I don't have statistics, but I think the ++ -- operators are a common source of bugs in C and C++ code. I know they are handy, but they ask me too much in turn. On the other hand that legacy C code usually works. If I have to convert C code like that to D-like, and D-like increment/decrement operators return void, this makes a large percentage of C code invalid D code, this will make _much_ harder for me to port C code to D-like. A little solution to this problem is to put a compiler switch (like the -d for deprecated features) that when present makes the ++ -- operators return a value, otherwise they return void. So using -d I am able to port C code to D-like, I slowly convert the code, and later I stop using -d for this converted code. --------------------- From the Go specs: http://golang.org/doc/go_spec.html As the ++ and -- operators form statements, not expressions, they fall outside the operator hierarchy. As a consequence, statement *p++ is the same as (*p)++. Go designers share some of my concerns on this. --------------------- In slide 215 it says C99 has introduced %zu to print size_t values with printf, I didn't know this. This D code seems to work: import core.stdc.stdio: printf; void main() { size_t x = 155; printf("%zu\n", x); } Bye, bearophile
Oct 10 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Sorry for the "typo" in the post Subject :-(

Oct 10 2011