On 5/16/22 08:18, Kevin Bailey wrote:
> I was asking, "Why is it this way? Why was it
> designed this way?
I for one misunderstood you. I really thought you were arguing that
struct and class should be the same.
> What bad thing happens the other way?"
C++ is proof that it can indeed work the other way. However, for it to
work correctly, programmers must follow guidelines. Here are four:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c67-a-polymorphic-class-should-suppress-public-copymove
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c145-access-polymorphic-objects-through-pointers-and-references
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-slice
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#e15-throw-by-value-catch-exceptions-from-a-hierarchy-by-reference
C++ does not use terms "value type" and "reference type" to make any
distinction but the rules above are proof enough for me that C++
implicitly divides user-defined types into such categories.
D is this way because someone realized that there are different kinds of
user-defined types.
> 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.)
Ok, I think I see better now. You would like members of a class
recursively placed next to each other in memory. What if a polymorphic
type had a polymorphic member?
class Student : Human {
double a;
Pet pet;
double b;
}
Could Pet (which could be a Cat or a Dog, etc.) fit between a and b?
Yes, emplacing the top-level object in our memory would have some value
but not all members would be there. For example, D's dynamic arrays are
like C++'s vector. What if the type had a vector? It's element would not
be on the stack.
Granted, the type could have a specific Pet:
Dog pet;
but I would argue that not all Students would have a Dog.
> 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.
I don't understand that example. I see a programmer error of casting a
Foo to a Bar.
> 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?
I thought more of this and conferred with a colleague who degisned parts
of Intel CPUs. He agrees with you: Even if passed by reference, the
objects are in CPU cache anyway and the pointer arithmetic is made in
the core that all is good.
He went further to suggest yes, by-reference will be faster for large
structs but there is no clear answer because it all depends on the
speeds of the core, cache (including the size), memory.
> D went the Java path: You can have any color you
> like, as long as it's grey.
Did you mean C#? C# is like D: structs are value types and classes are
reference types.
> 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.
Not at all!
> I've learned from all the projects that I've been on
> that we need all these types.
With all due respect, based on other conversation here, may I assume you
those projects were based on C++? If you also had any language with
reference types like Python, did you have the similar issues with those
languages?
I accepted D's struct/class separation since the beginning and never had
any issue with it. It just worked for me.
Ali