Biggest problems w/ D - struct/class
C. Dunn
cdunn2001 at gmail.com
Fri Aug 10 15:37:48 PDT 2007
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.
More information about the Digitalmars-d
mailing list