www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - C faults, etc

reply bearophile <bearophileHUGS lycos.com> writes:
There's a long thread on reddit about the faults of C language:
http://www.reddit.com/r/programming/comments/92l8w/in_your_opinions_what_is_wrong_with_the_c/

Some comments derived from it:

D already fixes/pathes several problems of C, but not all of them. One of the
problems is the pointer syntax and the problem coming from its operator
precedence. Pascal pointer syntax is a bit better. The famous "C++ resyntaxed"
shows a quite better pointer syntax. I'd like to see a better and less
bug-prone pointer syntax in D, but it's hard to change it and keep
almost-source-compatibility with C at the same time.

------------

Lint-like programs like Splint (http://www.splint.org ) help avoid some of the
problems of C, but from experience I can see people don't use such programs. So
D has to contain some of the things done by a lint. One of the important things
is a way to add some more semantics to programs, for example to say if two
pointers/slices/arrays are surely distinct, and many other things. (So far I
have not understood the D stance regarding pointer aliasing).

------------

D has now two switch, both of them faulty. This looks worse than the C
situation. I can't appreciate this situation.

------------

C comma operator is bad. Python shows a WAY better way to use commas, but if D
wants to keep its almost-source-compatibility with C then Python syntax may be
hard to be added. A partial solution I see is just to turn some usages of the
comma operator into a compilation error, just like in D it's an error legal C
syntax like:
int *i, j;

------------

Java shows that undefined behaviour can be avoided with an acceptable cost in
performance. So D eventually has to remove all situations where it acts in an
undefined way. Where it's really needed some non-standard way to do things can
be added. Better to have nonportable things than undefiend things.

------------

writefln, writeln and the things of Tango are nice and cute and safe, but if I
have to save 250 MB of numbers (or 1 GB of them, or even more) then performance
is important, and those cute functions are 2-3-5 times slower than printf. This
means printf can save me minutes of running time. So I use printf. But if I use
printf in C and I write:

int main() {
    float f = 1.2345;
    printf("%d\n", f);
    return 0;
}

The compiler says me:
warning: format '%d' expects type 'int', but argument 2 has type 'double'
While DMD compiles it silently. Better to quickly add such warning/error to D
compilers too.

Bye,
bearophile
Jul 20 2009
next sibling parent BCS <ao pathlink.com> writes:
Reply to bearophile,

 writefln, writeln and the things of Tango are nice and cute and safe,
 but if I have to save 250 MB of numbers (or 1 GB of them, or even
 more) then performance is important, and those cute functions are
 2-3-5 times slower than printf. This means printf can save me minutes
 of running time. So I use printf. But if I use printf in C and I
 write:
 
 int main() {
 float f = 1.2345;
 printf("%d\n", f);
 return 0;
 }
 The compiler says me:
 warning: format '%d' expects type 'int', but argument 2 has type
 'double'
 While DMD compiles it silently. Better to quickly add such
 warning/error to D compilers too.

It would be interesting to write a template that takes a static format string (using writef syntax) and, based on its argument tuple to generates a trivial wrapper around printf with a guarantied correct (printf syntax) format string.
Jul 20 2009
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
bearophile wrote:
 There's a long thread on reddit about the faults of C language:
 http://www.reddit.com/r/programming/comments/92l8w/in_your_opinions_what_is_wrong_with_the_c/
 
 Some comments derived from it:
 
 D already fixes/pathes several problems of C, but not all of them. One of the
problems is the pointer syntax and the problem coming from its operator
precedence. Pascal pointer syntax is a bit better. The famous "C++ resyntaxed"
shows a quite better pointer syntax. I'd like to see a better and less
bug-prone pointer syntax in D, but it's hard to change it and keep
almost-source-compatibility with C at the same time.

What are you talking about? There are numerous people complaining that defining pointer types is painful, but D fixes that. There's one person who complained about parsing ambiguities; was that what you were referring to? It doesn't help that you don't specify what the problem is.
 ------------
 
 Lint-like programs like Splint (http://www.splint.org ) help avoid some of the
problems of C, but from experience I can see people don't use such programs. So
D has to contain some of the things done by a lint. One of the important things
is a way to add some more semantics to programs, for example to say if two
pointers/slices/arrays are surely distinct, and many other things. (So far I
have not understood the D stance regarding pointer aliasing).

Neither Lint or Splint was mentioned ONCE in that thread.
 ------------
 
 D has now two switch, both of them faulty. This looks worse than the C
situation. I can't appreciate this situation.

Switch was brought up exactly once, but that was a comment regarding enums. You also haven't specified what the problem is.
 ------------
 
 C comma operator is bad. Python shows a WAY better way to use commas, but if D
wants to keep its almost-source-compatibility with C then Python syntax may be
hard to be added. A partial solution I see is just to turn some usages of the
comma operator into a compilation error, just like in D it's an error legal C
syntax like:
 int *i, j;

Comma operator was never brought up.
 ------------
 
 Java shows that undefined behaviour can be avoided with an acceptable cost in
performance. So D eventually has to remove all situations where it acts in an
undefined way.

While I think it should, I hardly see why the first demands the second.
 Where it's really needed some non-standard way to do things can be added.
Better to have nonportable things than undefiend things.

I'm fairly certain Walter has stated numerous times that one of the goals of D is to remove undefined behaviour. Why are you arguing for something which Walter already agrees with you on? One quick query with Google later: "One of the goals of D is to eliminate undefined behavior wherever possible. In C++, the undefined order of static construction was a source of many porting problems. I think it's better in the long run to have a defined order, even if it means having to reorganize the code a bit." http://www.digitalmars.com/d/archives/digitalmars/D/announce/Re_QtD_0.1_is_out_14928.html
 ------------
 
 writefln, writeln and the things of Tango are nice and cute and safe, but if I
have to save 250 MB of numbers (or 1 GB of them, or even more) then performance
is important, and those cute functions are 2-3-5 times slower than printf. This
means printf can save me minutes of running time. So I use printf. But if I use
printf in C and I write:

Firstly, if they're slower than printf, I imagine something is wrong. In Tango's case, I know it directly calls into the Win32 API. If it's 5 times slower than printf, something is horribly wrong, either with something along the way, or with your code. Did you file a ticket? Actually, let's check... (Goes off to test.) If you naively use tango.io.device.File and, say, to!(char[])(int), then D will take twice as long as C. That's because File is unbuffered and to!(char[])(int) uses a heap allocation. If you use a Buffered stream and use ...convert.Integer.format with a scratch buffer, D ends up being about 10% faster than C. This could be better documented, but Tango is *not* slow when used correctly.
 int main() {
     float f = 1.2345;
     printf("%d\n", f);
     return 0;
 }
 
 The compiler says me:
 warning: format '%d' expects type 'int', but argument 2 has type 'double'
 While DMD compiles it silently. Better to quickly add such warning/error to D
compilers too.

Why on earth should the D compiler special-case a function that's not even supposed to be used?! D has typesafe variadics and variadic templates.
 Bye,
 bearophile

None of these, with the possible exception of the pointer syntax one, had anything to do with that thread, so far as I can see.
Jul 20 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Daniel Keep:
Why on earth should the D compiler special-case a function that's not even
supposed to be used?!<

What's the purpose of being able to use the C std lib in D programs if then such functions aren't supposed to be used?
 Actually, let's check... (Goes off to test.)<

This is a first little test, with DMD V.2.031, on Windows, Phobos2: import std.stdio: printf; void main() { const int N = 2_000_000; for (int i; i < N; i++) printf("test %d\n", i); } A second version that uses writefln: import std.stdio: writefln; void main() { const int N = 2_000_000; for (int i; i < N; i++) writefln("test %d", i); } I have redirected their output to a file (26.2 MB file). The timings are: 1.16 seconds for the version with printf, and 14.93 seconds for the version with writefln. ----------------------- BCS:
It would be interesting to write a template that takes a static format string
(using writef syntax) and, based on its argument tuple to generates a trivial
wrapper around printf with a guarantied correct (printf syntax) format string.<

A nice idea, thanks. I may do that. Bye, bearophile
Jul 20 2009
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
bearophile wrote:

 Daniel Keep:
Why on earth should the D compiler special-case a function that's not even
supposed to be used?!<

What's the purpose of being able to use the C std lib in D programs if then such functions aren't supposed to be used?
 Actually, let's check... (Goes off to test.)<

This is a first little test, with DMD V.2.031, on Windows, Phobos2: import std.stdio: printf; void main() { const int N = 2_000_000; for (int i; i < N; i++) printf("test %d\n", i); } A second version that uses writefln: import std.stdio: writefln; void main() { const int N = 2_000_000; for (int i; i < N; i++) writefln("test %d", i); } I have redirected their output to a file (26.2 MB file). The timings are: 1.16 seconds for the version with printf, and 14.93 seconds for the version with writefln.

writefln does a flush where writef doesn't. On my system (fedora 11) all timings are nearly the same however, while writef is actually a bit faster than printf. What OS are you on?
Jul 20 2009
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Oh shit I forgot to redirect. That made my timings useless.

This one is about 8x faster than writefln, flushing seems to be quite  
expensive:

const int N = 2_000_000;
for (int i; i < N; i++)
	writef("test %d\n", i);
Jul 20 2009
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Lutger:
 writefln does a flush where writef doesn't. On my system (fedora 11) all 
 timings are nearly the same however, while writef is actually a bit faster 
 than printf. What OS are you on?

I am doing such tests on an unloaded Windows 32 bit XP SP2, on a Core2 at 2 GHz and 2 GB RAM. I have done another test for writeln, and indeed it's quite faster than writefln, it takes 2.45 seconds: import std.stdio: writeln; void main() { const int N = 2_000_000; for (int i; i < N; i++) writeln("test ", i); } Bye, bearophile
Jul 20 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, Jul 20, 2009 at 12:22 PM, BCS<ao pathlink.com> wrote:
 It would be interesting to write a template that takes a static format
 string (using writef syntax) and, based on its argument tuple to generates a
 trivial wrapper around printf with a guarantied correct (printf syntax)
 format string.

Oh, you mean something like this? http://github.com/wilkie/xomb/blob/98f612085516d644d03bb464224fa37c9d8f2926/kernel/core/kprintf.d teeheehee
Jul 20 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 writefln, writeln and the things of Tango are nice and cute and safe, but if I
have to save 250 MB of numbers (or 1 GB of them, or even more) then performance
is important, and those cute functions are 2-3-5 times slower than printf. This
means printf can save me minutes of running time. So I use printf. But if I use
printf in C and I write:
 
 int main() {
     float f = 1.2345;
     printf("%d\n", f);
     return 0;
 }
 
 The compiler says me:
 warning: format '%d' expects type 'int', but argument 2 has type 'double'

This is a non-standard extension to C.
 While DMD compiles it silently. Better to quickly add such warning/error to D
compilers too.

D's answer to printf and its problems is writefln.
Jul 20 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 This is a non-standard extension to C.

Thanks god there are people (compiler writers, like GCC devs) that think the C standard is not a Holy Text given to us by God :-) They improve C where it has holes and limits, so it can be more useful for most practical purposes. Language lawyers can eat their hats. And even if C standard is sacred and you can never touch it, D isn't C, and C functions that can be used from D can keep the C interfaces but improve the situation in some ways.
 D's answer to printf and its problems is writefln.<

Then we have to work on the efficiency of its implementation :-) (See my timings lower in this thread). Bye, bearophile
Jul 20 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Then we have to work on the efficiency of its implementation :-) (See my
timings lower in this thread).

I've implemented printf. There is nothing fundamental about its efficiency that would be any better than writefln. If writefln is slower, it's due to a bug, not anything fundamental.
Jul 20 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 20 Jul 2009 20:41:03 -0400, Walter Bright  
<newshound1 digitalmars.com> wrote:

 bearophile wrote:
 Then we have to work on the efficiency of its implementation :-) (See  
 my timings lower in this thread).

I've implemented printf. There is nothing fundamental about its efficiency that would be any better than writefln. If writefln is slower, it's due to a bug, not anything fundamental.

Part of it could be fundamental. * D deals with UTF, whereas printf does not * Phobos calls the C runtime, so it's guaranteed never to beat printf, since printf is not type-safe, and therefore does less. * Both Tango and Phobos output functions make use of delegates to output data. In the case of Phobos, it uses a delegate to call the C runtime's "delegate" fputc, so it's going to be double the delegate penalty for each character. If you're measuring the performance of millions of writes, then you will see even a slight difference. Bearophile, You may want to develop a more specialized function to do file output if you are writing such large quantities of uniform data, calling the system calls directly, it might even beat printf. -Steve
Jul 21 2009