www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Biggest problems w/ D

reply C. Dunn <cdunn2001 gmail.com> writes:
After converting a large, system-level program to D, I can name the biggest
problems:

1) No stack-trace on exceptions.
This makes contract programming a mere QA test, rather than a useful debugging
tool.

2) No 64-bit support.
This not only limits memory usage, but also causes 2x runtime on my AMD
processor.  My D code is the same speed as my 32-bit C++ code, but both are 2x
slower than 64-bit C++ code.  Same compiler.  Same machine.

3) Lack of forward declarations.
The compiler figures everything out in simple cases, but it gets very confused
with templates.  That dramatically hurts the genericity of D, since it limits
what templates can do.  One nice use of templates in C++ is to set a static
variable on a type, as a sort of "property" with high-speed access.  With D, I
have accomplished this only by putting all templates in the same file.

This problem also causes the compiler to depend on the order of files on the
command-line.

4) Not enough help for converting between D strings and C char*.
There must be conversion functions which work regardless of whether the D
string is dynamic or not, and regardless of whether the C char* is null
terminated.  I'm not sure what the answer is, but this has lead to a large
number of runtime bugs for me as a novice.

5) Same syntax structs and classes.
This is minor problem, but it is extremely confusing to the novice.  A struct
and a class are completely different in D, but the fact that I can write code
the same to use either one implies too much similarity.  It leads to
programming errors which easily result in seg-fault.

Also, it is too difficult to switch a set of objects from structs to classes or
vice versa.  I need to be able to do that in order to compare runtimes for
various implementations.  Again, I don't know the best answer.


I love the language as an evolution of C++, so I really hope these problems get
ironed out.  I could list a *lot* of great things about D!
Aug 09 2007
next sibling parent Jascha Wetzel <firstname mainia.de> writes:
C. Dunn wrote:
 1) No stack-trace on exceptions.
 This makes contract programming a mere QA test, rather than a useful debugging
tool.

on windows you can use ddbg (http://ddbg.mainia.de) to get full stack-traces for all exceptions
Aug 09 2007
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
C. Dunn Wrote:


 5) Same syntax structs and classes.
 This is minor problem, but it is extremely confusing to the novice.  A struct
and a class are completely different in D, but the fact that I can write code
the same to use either one implies too much similarity.  It leads to
programming errors which easily result in seg-fault.
 
 Also, it is too difficult to switch a set of objects from structs to classes
or vice versa.  I need to be able to do that in order to compare runtimes for
various implementations.  Again, I don't know the best answer.

I agree with the rest of your post, but IMO this would make using classes confusing, C++-style. Structs as value-types and classes as reference-types is one of the hallmarks of D and value types + inheritance just makes everything harder (slicing, etc.), and one of D's advantages is that it's a lot simpler to do what you want without ambiguity. Just my opinion, though. I esp. agree on stack tracing, though. Debuggers are nice, but not everyone runs their code under a debugger all the time. I tried Tango + Flectioned, which ran great under Linux, but since I develop on/for Windows, this isn't helpful.
Aug 09 2007
prev sibling next sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
C. Dunn wrote:
 4) Not enough help for converting between D strings and C char*. 
 There must be conversion functions which work regardless of whether
 the D string is dynamic or not, and regardless of whether the C char*
 is null terminated.  I'm not sure what the answer is, but this has
 lead to a large number of runtime bugs for me as a novice.
 

The std.string module has the toStringz and toString functions. The toString function simply returns a slice over the C string: char[] toString(char* ptr) { return ptr[0 .. strlen(ptr)]; } The toStringz function simply appends a null character (\0) to the end of the D string: char* toStringz(char[] str) { return (str ~ \0).ptr; } These are very simple operations, and it is fairly easy to adapt them to whatever needs you have.
 5) Same syntax structs and classes. This is minor problem, but it is
 extremely confusing to the novice.  A struct and a class are
 completely different in D, but the fact that I can write code the
 same to use either one implies too much similarity.  It leads to
 programming errors which easily result in seg-fault.
 
 Also, it is too difficult to switch a set of objects from structs to
 classes or vice versa.  I need to be able to do that in order to
 compare runtimes for various implementations.  Again, I don't know
 the best answer.
 

Structs and classes are very different beasts in D, even if they look the same. However, there are some important differences in their use which should clue you in: Using 'new' on a class gives you a reference, using it on a struct gives you a pointer. Structs are plain ol' data. Saying "SomeStruct s;" gives you an instance you can immediately behind using. You have to use 'new' to get a class instance. Classes have inheritance and all those other object-oriented features, while structs do not. What I am getting at is that whether something should be a class or a struct seems like an important design decision which shouldn't be expected to change after development is well underway. Also, code doesn't really look all that similar when it uses structs vs. classes.
 
 I love the language as an evolution of C++, so I really hope these
 problems get ironed out.  I could list a *lot* of great things about
 D!
 

-- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Aug 09 2007
next sibling parent reply Tristam MacDonald <swiftcoder gmail.com> writes:
Kirk McDonald wrote:
 C. Dunn wrote:
 
 5) Same syntax structs and classes. This is minor problem, but it is
 extremely confusing to the novice.  A struct and a class are
 completely different in D, but the fact that I can write code the
 same to use either one implies too much similarity.  It leads to
 programming errors which easily result in seg-fault.

 Also, it is too difficult to switch a set of objects from structs to
 classes or vice versa.  I need to be able to do that in order to
 compare runtimes for various implementations.  Again, I don't know
 the best answer.

Structs and classes are very different beasts in D, even if they look the same. However, there are some important differences in their use which should clue you in: Using 'new' on a class gives you a reference, using it on a struct gives you a pointer. Structs are plain ol' data. Saying "SomeStruct s;" gives you an instance you can immediately behind using. You have to use 'new' to get a class instance. Classes have inheritance and all those other object-oriented features, while structs do not. What I am getting at is that whether something should be a class or a struct seems like an important design decision which shouldn't be expected to change after development is well underway. Also, code doesn't really look all that similar when it uses structs vs. classes.

I don't agree here. I had all my algebraic classes (vectors, matrices, transforms, etc.) as structs, as they needed to be value types, and for performance. However, I had to convert several of the more complex structs to classes instead, when I needed reference semantics. Since structs use a different constructor syntax, along with 'this' versus '*this', it was quite annoying. Since the only difference the original spec highlighted was that one in a reference type, and one a value type, it seems silly to have large syntactical differences between them. In particular, that structs lack meaningful constructors/destructors/copying semantics is *really* annoying. Value types are scoped, so why not let us use that to our advantage?
Aug 09 2007
parent "Craig Black" <craigblack2 cox.net> writes:
"Tristam MacDonald" <swiftcoder gmail.com> wrote in message 
news:f9gm20$2jd6$1 digitalmars.com...
 Kirk McDonald wrote:
 C. Dunn wrote:

 5) Same syntax structs and classes. This is minor problem, but it is
 extremely confusing to the novice.  A struct and a class are
 completely different in D, but the fact that I can write code the
 same to use either one implies too much similarity.  It leads to
 programming errors which easily result in seg-fault.

 Also, it is too difficult to switch a set of objects from structs to
 classes or vice versa.  I need to be able to do that in order to
 compare runtimes for various implementations.  Again, I don't know
 the best answer.

Structs and classes are very different beasts in D, even if they look the same. However, there are some important differences in their use which should clue you in: Using 'new' on a class gives you a reference, using it on a struct gives you a pointer. Structs are plain ol' data. Saying "SomeStruct s;" gives you an instance you can immediately behind using. You have to use 'new' to get a class instance. Classes have inheritance and all those other object-oriented features, while structs do not. What I am getting at is that whether something should be a class or a struct seems like an important design decision which shouldn't be expected to change after development is well underway. Also, code doesn't really look all that similar when it uses structs vs. classes.

I don't agree here. I had all my algebraic classes (vectors, matrices, transforms, etc.) as structs, as they needed to be value types, and for performance. However, I had to convert several of the more complex structs to classes instead, when I needed reference semantics. Since structs use a different constructor syntax, along with 'this' versus '*this', it was quite annoying. Since the only difference the original spec highlighted was that one in a reference type, and one a value type, it seems silly to have large syntactical differences between them. In particular, that structs lack meaningful constructors/destructors/copying semantics is *really* annoying. Value types are scoped, so why not let us use that to our advantage?

Agreed. I think Walter has plans to add constructors/destructors/copying semantics to structs. It's a welcome change. -Craig
Aug 09 2007
prev sibling next sibling parent reply Gilles G. <schaouette free.fr> writes:
Kirk McDonald Wrote:

 C. Dunn wrote:
 4) Not enough help for converting between D strings and C char*. 
 There must be conversion functions which work regardless of whether
 the D string is dynamic or not, and regardless of whether the C char*
 is null terminated.  I'm not sure what the answer is, but this has
 lead to a large number of runtime bugs for me as a novice.
 

The std.string module has the toStringz and toString functions. The toString function simply returns a slice over the C string: char[] toString(char* ptr) { return ptr[0 .. strlen(ptr)]; } The toStringz function simply appends a null character (\0) to the end of the D string: char* toStringz(char[] str) { return (str ~ \0).ptr; } These are very simple operations, and it is fairly easy to adapt them to whatever needs you have.

I have a DLL defining the following (extern) function: extern(Windows) void GetName(char* name) I would just like to put the name of the DLL in the variable name. What I would do in C is something like: extern(Windows) void GetName(char* name) { name = "The DLL name"; } This just won't work in D... My solution for now is the following: extern(Windows) void GetName(char* name) { foreach(ic, c; "The DLL name\0") name[ic]=c; } which is ugly, but do you have a better solution? --Gilles
Aug 10 2007
next sibling parent reply Paul Findlay <r.lph50+d gmail.com> writes:
 I would just like to put the name of the DLL in the variable name. What I
 would do in C is something like:
      extern(Windows) void GetName(char* name)
      {
           name = "The DLL name";
      }

const char[] DLL_NAME = "The DLL name"; extern(Windows) void GetName(char* name) {     name = DLL_NAME.ptr; } work? - Paul
Aug 10 2007
parent reply Gilles G. <schaouette free.fr> writes:
Paul Findlay Wrote:

 I would just like to put the name of the DLL in the variable name. What I
 would do in C is something like:
      extern(Windows) void GetName(char* name)
      {
           name = "The DLL name";
      }

const char[] DLL_NAME = "The DLL name"; extern(Windows) void GetName(char* name) { name = DLL_NAME.ptr; } work?

I tried: const char[15] DLL_NAME="The DLL name"; extern(Windows) void GetName(char* name) { name = DLL_NAME.ptr; }
Aug 10 2007
parent reply Paul Findlay <r.lph50+d gmail.com> writes:
 Unfortunately, no.
 I tried:
 const char[15] DLL_NAME="The DLL name";

is the problem), so you could also try: name = "The DLL Name".ptr Sorry about this being the blind leading the blind.. - Paul
Aug 10 2007
parent reply Gilles G. <schaouette free.fr> writes:
Paul Findlay Wrote:

 Unfortunately, no.
 I tried:
 const char[15] DLL_NAME="The DLL name";

is the problem), so you could also try: name = "The DLL Name".ptr Sorry about this being the blind leading the blind..

(In fact I tried const char[15] DLL_NAME="The DLL name\0"; )
 
  - Paul

Aug 10 2007
parent Paul Findlay <r.lph50+d gmail.com> writes:
Umm can we review what you are tying to do.. because if its something like
this (C version)

#include <stdio.h>

void GetName(char *name)
{
        name = "The right one";
}

int main()
{
        char *name = "the original";
        GetName(name);
        printf("%s\n", name);
}

it will print: the original

If you want name to hold "the right one" it will need to be a pointer to a
pointer:

#include <stdio.h>

void GetName(char **name)
{
        *name = "The right one";
}

int main()
{
        char *name = "the original";
        GetName(&name);
        printf("%s\n", name);
        // will print: The right one
}

Otherwise, I give up..
Aug 10 2007
prev sibling next sibling parent Radu <radu.racariu void.space> writes:
is this working for you?

extern(Windows) void GetName(ref char* name)
{
    name = "just modified".ptr;
}

void main ()
{
    char* cpt = "initial value".ptr;
    GetName(cpt);
    printf("%s",cpt);
}

Gilles G. wrote:
 Kirk McDonald Wrote:

   
 C. Dunn wrote:
     
 4) Not enough help for converting between D strings and C char*. 
 There must be conversion functions which work regardless of whether
 the D string is dynamic or not, and regardless of whether the C char*
 is null terminated.  I'm not sure what the answer is, but this has
 lead to a large number of runtime bugs for me as a novice.

       

The toString function simply returns a slice over the C string: char[] toString(char* ptr) { return ptr[0 .. strlen(ptr)]; } The toStringz function simply appends a null character (\0) to the end of the D string: char* toStringz(char[] str) { return (str ~ \0).ptr; } These are very simple operations, and it is fairly easy to adapt them to whatever needs you have.

I have a DLL defining the following (extern) function: extern(Windows) void GetName(char* name) I would just like to put the name of the DLL in the variable name. What I would do in C is something like: extern(Windows) void GetName(char* name) { name = "The DLL name"; } This just won't work in D... My solution for now is the following: extern(Windows) void GetName(char* name) { foreach(ic, c; "The DLL name\0") name[ic]=c; } which is ugly, but do you have a better solution? --Gilles

Aug 10 2007
prev sibling parent BCS <ao pathlink.com> writes:
Reply to Gilles G.,

 Kirk McDonald Wrote:
 
 C. Dunn wrote:
 
 4) Not enough help for converting between D strings and C char*.
 There must be conversion functions which work regardless of whether
 the D string is dynamic or not, and regardless of whether the C
 char* is null terminated.  I'm not sure what the answer is, but this
 has lead to a large number of runtime bugs for me as a novice.
 

The toString function simply returns a slice over the C string: char[] toString(char* ptr) { return ptr[0 .. strlen(ptr)]; } The toStringz function simply appends a null character (\0) to the end of the D string: char* toStringz(char[] str) { return (str ~ \0).ptr; } These are very simple operations, and it is fairly easy to adapt them to whatever needs you have.

the problems I had with char[] and char*. I have a DLL defining the following (extern) function: extern(Windows) void GetName(char* name) I would just like to put the name of the DLL in the variable name. What I would do in C is something like: extern(Windows) void GetName(char* name) { name = "The DLL name"; } This just won't work in D... My solution for now is the following: extern(Windows) void GetName(char* name) { foreach(ic, c; "The DLL name\0") name[ic]=c; } which is ugly, but do you have a better solution? --Gilles

if you are passing a buffer this should work extern(Windows) GetName(char* buf) // should have length to { static const char[] n = "The DLL name\0"; buf[0..n.length]=n[]; }
Aug 10 2007
prev sibling parent reply C. Dunn <cdunn2001 gmail.com> writes:
Kirk McDonald Wrote:

 Structs and classes are very different beasts in D, even if they look 
 the same. However, there are some important differences in their use 
 which should clue you in:
 
 Using 'new' on a class gives you a reference, using it on a struct gives 
 you a pointer.
 
 Structs are plain ol' data. Saying "SomeStruct s;" gives you an instance 
 you can immediately behind using. You have to use 'new' to get a class 
 instance.
 
 Classes have inheritance and all those other object-oriented features, 
 while structs do not.
 
 What I am getting at is that whether something should be a class or a 
 struct seems like an important design decision which shouldn't be 
 expected to change after development is well underway. Also, code 
 doesn't really look all that similar when it uses structs vs. classes.

When converting C++ to D, the choice of struct or class is not so obvious. struct has performance advantages, and testing may be required to decide whether that advantage is significant in context. I would like to typedef (or alias) like this: struct S{} class C{} version(fast){ alias C Foo; }else{ alias S* Foo; } The problem is that, since S lacks ctor/dtor, I have to rewrite my code substantially. If you doubt the performance difference, try this: static import std.stdio; static import std.c.stdlib; struct A{ int x = 57; void set(int y){ x = y; } }; void foo(uint n){ auto all = new A*[n]; uint c = n; while(c--){ all[c] = new A; } c = n; while(c--){ assert(all[c].x == 57); all[c].set(c); assert(all[c].x == c); } c = n; while(c--){ delete all[c]; } } class B{ int x = 57; void set(int y){ x = y; } }; void bar(uint n){ auto all = new B[n]; uint c = n; while(c--){ all[c] = new B; } c = n; while(c--){ assert(all[c].x == 57); all[c].set(c); assert(all[c].x == c); } c = n; while(c--){ delete all[c]; } } int main(char[][] args) { uint n = 1; if (args.length>1){ n = std.c.stdlib.atoi(args[1].ptr); } //foo(n); bar(n); std.stdio.writefln("Done ", n); return 0; } [Here, I do not need ctors, since I have initializers.] Use either foo() or bar(). With normal compilation, I get a 10% slow-down for the class. With "-O -inline -release", I get 10% to 20%, and it's not even consistent. Sometimes 10% is important, especially for system-level tasks. One could fear an even bigger hit, so the ability to do comparative testing is important. Someone said that Walter is adding ctors to structs. That would help. But note that I cannot write generic code! operator new() returns different things in different situations!! If I try to use an alias or a typedef to switch between A* (pointer to struct A) and B (ref to class B), I cannot call new on the alias: version(A){ alias A* Foo; }else{ alias B Foo; } Foo x = new Foo; This does not work!!!!!!!!!! Hopefully, you can now see the problem. This is a big impediment in converting C++ code to D, and not just b/c of the runtime difference. The natural thing is to convert C-style structs to D structs, using std.c.stdlib.malloc()/free(). Then, during refactoring, a person might say, "Hmmm. Maybe it would be cool to use D classes instead." But the "refactoring" is a huge pain in the arse because of this inconsistency. When Foo is a struct, the syntax should be "new Foo*()", not "new Foo()". That completely solves the problem, but breaks existing code. Solution: "operator New" with a capital N. It's important to recognize that D is just an OK language all by itself. Its great potential comes from its close resemblance to C++, making the transistion possible. Smooth code re-factoring is extemely important if you want C++ coders to adopt D.
Aug 10 2007
parent BCS <ao pathlink.com> writes:
Reply to C. Dunn,

 
 struct S{}
 class C{}
 version(fast){
 alias C Foo;
 }else{
 alias S* Foo;
 }
 The problem is that, since S lacks ctor/dtor, I have to rewrite my
 code substantially.
 

For ctor you could use a static method to wrap the new for both cases. Not vary clean but the performance hit should be the same for both sides. For dtor, no such luck. Then again I have yet to ever use a dtor in D.
Aug 10 2007
prev sibling next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
C. Dunn wrote:
 After converting a large, system-level program to D, I can name the biggest
problems:

 2) No 64-bit support. This not only limits memory usage, but also
 causes 2x runtime on my AMD processor.  My D code is the same speed
 as my 32-bit C++ code, but both are 2x slower than 64-bit C++ code.
 Same compiler.  Same machine.

Been asked for many-a-time. I believe GDC, now supports 64-bit compilation. http://dgcc.sourceforge.net/ The problem is that the linker used by DMD is some ancient thing written in assembly that ain't never gonna get upgraded to 64bit. A new linker must be found or written eventually. Unless someone interested in helping with that comes out of the woodwork, it's probably going to mean a 6-12 month halt in progress for D as Walter goes off to write a new linker. I think few people want that to happen to D, at least not until the language has all its issues pretty much worked out.
 3) Lack of forward declarations. The compiler figures everything out
 in simple cases, but it gets very confused with templates.  That
 dramatically hurts the genericity of D, since it limits what
 templates can do.  One nice use of templates in C++ is to set a
 static variable on a type, as a sort of "property" with high-speed
 access.  With D, I have accomplished this only by putting all
 templates in the same file.
 
 This problem also causes the compiler to depend on the order of files
 on the command-line.

Been asked for many-a-time. I think the problem is again the black-box linker that no one knows how to fix. --bb
Aug 09 2007
prev sibling next sibling parent renoX <renosky free.fr> writes:
C. Dunn a crit :
 After converting a large, system-level program to D, I can name the
 biggest problems:

 2) No 64-bit support. This not only limits memory usage, but also
 causes 2x runtime on my AMD processor.  My D code is the same speed
 as my 32-bit C++ code, but both are 2x slower than 64-bit C++ code.
 Same compiler.  Same machine.

2x? Your code must do a lot of 64b computation! When the AMD64 was released benchmarks made showed at best a 20% improvement, which is quite a lot to get with a simple recompilation assuming the code is 64b clean of course but is nowhere 2x. Either your code makes a lot of 64b computations or there are issue on the 32b version of your C++ code. That said, its a problem with DMD not with D, if memory serves GDC supports 64b code generation. renoX
Aug 09 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
 Been asked for many-a-time. I believe GDC, now supports 64-bit 
 compilation.   http://dgcc.sourceforge.net/

At least for me 64 bit gdc works very fine atm (on linux).
 Been asked for many-a-time.  I think the problem is again the
 black-box linker that no one knows how to fix.

Would it be easier/less work to have dmd output the "standard" windows object format then write a new linker? (I dont remember the exact name of that beast) I mean finding linkers for that wouldnt be too hard (iirc lcc has one, there is a free one from M$ etc...) and on linux there is no problem anyway as the object format is already the "standard one". Henning -- GPG Public Key: http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851 Fingerprint: 344F 4072 F038 BB9E B35D E6AB DDD6 D36D 4191 1851
Aug 10 2007
prev sibling next sibling parent Frank Benoit <keinfarbton googlemail.com> writes:
C. Dunn schrieb:
 1) No stack-trace on exceptions.
 This makes contract programming a mere QA test, rather than a useful debugging
tool.
 

Since I use flectioned, i have stack traces for exceptions and segmentation faults. I havn't tested it with DBC.
Aug 10 2007
prev sibling parent reply "Alvaro GP" <alvaro liteapplications.com> writes:
Sorry for being a little offtopic, but I saw your post and I was wondering 
if you are Corbin Dunn, ex Borland employee.

It's pretty exciting to see you using the D language. I'm sure that this 
encourages us to embrace it above the difficulties.
Aug 10 2007
parent Stephen Waits <steve waits.net> writes:
Alvaro GP wrote:
 Sorry for being a little offtopic, but I saw your post and I was wondering 
 if you are Corbin Dunn, ex Borland employee.
 
 It's pretty exciting to see you using the D language. I'm sure that this 
 encourages us to embrace it above the difficulties.

If it is the same guy, he works for Apple now. I'd love to hear we have a D Evangelist (or two) in Cupertino. Also looks like a fellow ERAU dropout. Anyway, here's his site: http://www.corbinstreehouse.com/ --Steve
Aug 12 2007