Why are structs and classes so different?

Kevin Bailey keraba at yahoo.com
Mon May 16 15:18:11 UTC 2022


Great responses, everyone. I'll try to address all of them.

Mike, I know the rules. I was asking, "Why is it this way? Why 
was it designed this way? What bad thing happens the other way?" 
When I think about most things in D, I can at least think of a 
reason, even if I don't agree with it. But not putting class 
objects on the stack makes no sense to me (assuming we still pass 
by reference.) Reasons below.

Ola, your response is very interesting. I would say that 
assignment isn't any more or less of an issue, as long as you 
pass by reference:

// Using C syntax to make intent clear.
class Foo { int x; }
class Bar: Foo { int y; }

void func1(Bar* bar) {
   bar.y = 4; // boom
}

void func2(Bar* bar) {
   Foo* foo = bar;
   foo.x = 3; // this is fine

   foo = new Foo;
   func1(cast(Bar*)(foo)); // uh oh
}

Illuminating comment about the ABI.

Ali, I've never liked the distinction between 'struct' and 
'class' in C++ either, but that's no reason to actually make them 
different. It's a reason to remove 'class' and save the keyword.

re: pass-by-reference and performance, agreed, this is why we 
pass integers in registers. But a struct on the stack is just as 
fast to access locally through a pointer register - "[bp+6]" - as 
remotely, yes?

Finally, 'scope' is nice but it doesn't solve the segfault issue.

HS Teoh: See above for my responses about assignment and 'scope'.

bauss: "But that's not entirely true as you can allocate a struct 
on the heap as well."

forkit: "where they live in memory should be less of the 
programmers concern, and more an implementation issue (although 
some programmers will of course consider this as well)."

Precisely. You can allocate structs, and you can put class 
objects in 'scope' variables. (I'm not sure if this was your 
intent, forkit, but) a class object can live on the stack just as 
easily as on the heap, as long as you pass by reference. The only 
danger is if a called function tries to own a stack allocated 
object, but this is a concern for heap allocated objects too. 
This is why C++ has moveable types and unique_ptr.

Walter, Thanks for the insightful reply! I'm getting the sense 
that the decision was made in order to make the language simpler. 
That is, ignoring struct's, D went the Java path: You can have 
any color you like, as long as it's grey.

I agree that C++'s organic growth allows programmers to do things 
they shouldn't, and requires that they be more careful. But I 
would not have gone from there to Java.

I think an interesting middle-ground would be a language that had 
"template" types - Copyable, MoveOnly, Interface, Singleton, 
FactoryBuilt, etc. I've learned from all the projects that I've 
been on that we need all these types. We can either ask 
programmers to hand-craft them, or we can provide them. Note that 
in C++, we can get pretty close:

class Foo: Moveable<Foo> { ...

And then there's the segfault issue. I think that, if we're going 
to ignore a huge problem like that, there has to be very strong 
reasons. From this discussion, it doesn't sound like they were 
very strong.

Of course, it's done and there's little changing it. A seemingly 
harmless fix would be to not require 'new':

Foo foo; // this allocates an object
Foo foo = null; // this does not
Foo foo = function(); // this doesn't either

In fact, I suspect we could make that change today and few would 
notice. Nevertheless, I'm still a little shocked that this isn't 
existing behavior.

cheers all



More information about the Digitalmars-d-learn mailing list