Hi again Ali!

On Monday, 16 May 2022 at 21:58:09 UTC, Ali Çehreli wrote:

I for one misunderstood you. I really thought you were arguing that struct and class should be the same.

To be specific:
- My *primary* concern is that:

Foo foo;

is undefined behavior waiting to happen, that I can't detect at a glance.

- A *secondary* goal would be for class objects to be able to have deterministic destructors like structs.

The first looks trivial: Just have it allocate a Foo by default.

The second looks like it could have been designed that way, albeit with other minor changes to the language, and, I was curious why it wasn't.

C++ is proof that it can indeed work the other way. However, for it to work correctly, programmers must follow guidelines. Here are four:

But again, from this discussion, it seems D could have simply had pass-by-reference for class objects, preserving everything D strives for, but by-value stack initialization, providing what people expect from stack objects. There's no need to drag C++ design into it.

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.

I would beg to differ here. In C++, all types are value types, until you add punctuation. This is one of the things that I like about C++, that I trip over in other languages. e.g. In Rust, there are 2 similar types, is it int and float, where one is copyable and the other move-only? How can you write generic code in that environment?

Yes, in C++, you have to worry about slicing and copying singletons, but these are problems in front of you. It's the problems that sneak up behind you that I worry about.

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?

You mean like a string? I don't have a problem with this:

class MyString {
   uint length;
   ...pointer to data...
}

void func() {
   MyString s;
   if (s.length == 0)  // I want this to be perfectly safe.
      writeln("empty");
   // 's' destroyed here, could do something useful
}

In D, some objects can do this; some can't!

I don't understand that example. I see a programmer error of casting a Foo to a Bar.

Correct, I was responding to a comment. I was pointing out that the only "slicing" that we need to worry about with by-reference is if we are already doing something wrong, and that D won't help you there.

Did you mean C#? C# is like D: structs are value types and classes are reference types.

You missed the part where I said, "ignoring structs". :-)

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?

Python is a toy language, right? I'm not aware of any large projects in it. (The largest I worked with was 138 files, 31k lines - tiny.)

Java would be a better comparison, but it has auto-closable objects, unlike D and Python. Perhaps it has succeeded because there are so few types that *aren't* by reference. Perhaps one just gets used to it. (I've written Android apps, but I would never write a long-running service in it.)

This is unfortunate for D where you have to keep track.

I accepted D's struct/class separation since the beginning and never had any issue with it. It just worked for me.

Perhaps you are familiar with the types that you work with on a daily basis. Perhaps the project is small. Perhaps your IDE colors classes brightly. I don't know, but an anecdote doesn't mean much compared to the fact that nearly all large projects are in C++, and I don't mean "due to inertia." I mean, "and they're successful."

Reply via email to