This Reddit thread:
http://www.reddit.com/r/programming/comments/l6yn1/deep_c_and_c_slides/

Has let me find this curious pack of slides about C and C++:
http://good.net/dl/au/061c/deepcslidesoct2012-111010033910-phpapp01.pdf

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:
http://www.reddit.com/r/programming/comments/l6yn1/deep_c_and_c_slides/c2qe43i

>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

Reply via email to