www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What would break if class was merged with struct

reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
I wonder, what would break if all the features of class was 
merged into struct?

Imagine that:

     class Something ... { ... }

is lowered into:

     struct _class_Something ... { ... }
     alias Something = MagicClassRef!_class_Something;

Is it conceivable with some language changes, a bit of automated 
source updating and a little bit of breakage?
May 27 2017
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 14:12:09 UTC, Ola Fosheim Grøstad 
wrote:
 I wonder, what would break if all the features of class was 
 merged into struct?

 Imagine that:

     class Something ... { ... }

 is lowered into:

     struct _class_Something ... { ... }
     alias Something = MagicClassRef!_class_Something;

 Is it conceivable with some language changes, a bit of 
 automated source updating and a little bit of breakage?
It's not "a little bit", it's ABI down the drain, along with a good part of runtime. And we'd lose interfaces and extern(C++). That being said, it is totally possible today to have struct wrappers over classes, both malloc'ed and stack-allocated. The problem is that destruction is always system (due to reasons described in my "Destructor attribute inheritance" thread: http://forum.dlang.org/thread/wtxkfylodzaaifojaglr forum.dlang.org). And one has to adopt a discipline not to escape references. Once DIP1000 is fully realized, at least the latter part will become unnecessary.
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 16:04:42 UTC, Stanislav Blinov wrote:
 It's not "a little bit", it's ABI down the drain, along with a 
 good part of runtime. And we'd lose interfaces and extern(C++).
Why would you loose interfaces and extern(C++)? "struct" and "class" are interchangeable keywords in C++ (only affects encapsulation). So not a lot more difference than POD vs non-POD in C++?
 That being said, it is totally possible today to have struct 
 wrappers over classes, both malloc'ed and stack-allocated.
Well, I am asking more out of a theoretical interest for what the core language in D could boil down to.
May 27 2017
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 16:23:33 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 16:04:42 UTC, Stanislav Blinov 
 wrote:
 It's not "a little bit", it's ABI down the drain, along with a 
 good part of runtime. And we'd lose interfaces and extern(C++).
Why would you loose interfaces and extern(C++)? "struct" and "class" are interchangeable keywords in C++ (only affects encapsulation). So not a lot more difference than POD vs non-POD in C++?
There's a lot more difference in D. Classes in D are fat memory chunks storing pointers to ClassInfo (inc. vtable), Monitor (i.e. for "synchronized") and a list of all interfaces they implement, that's before we get to data members. If we were to remove all that, we'd lose the semi-natural way of interfacing to C++ classes, and some pretty horrendous code involving void* and void** would have to be used.
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 16:31:32 UTC, Stanislav Blinov wrote:
 There's a lot more difference in D. Classes in D are fat memory 
 chunks storing pointers to ClassInfo (inc. vtable),
So are classes with virtual functions in C++, to get RTTI you need to have a virtual member function. I don't see the big difference.
 Monitor (i.e. for "synchronized") and
Wasn't this going to be removed?
 a list of all interfaces they implement,
Semantically roughly the same as multiple-inheritance in C++ but more limited.
 If we were to remove all that, we'd lose the semi-natural way 
 of interfacing to C++ classes, and some pretty horrendous code 
 involving void* and void** would have to be used.
I don't understand what you mean here.
May 27 2017
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 16:37:04 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 16:31:32 UTC, Stanislav Blinov 
 wrote:
 There's a lot more difference in D. Classes in D are fat 
 memory chunks storing pointers to ClassInfo (inc. vtable),
So are classes with virtual functions in C++, to get RTTI you need to have a virtual member function. I don't see the big difference.
But structs in D have none of that.
 Monitor (i.e. for "synchronized") and
Wasn't this going to be removed?
Not that I'm aware of.
 a list of all interfaces they implement,
Semantically roughly the same as multiple-inheritance in C++ but more limited.
 If we were to remove all that, we'd lose the semi-natural way 
 of interfacing to C++ classes, and some pretty horrendous code 
 involving void* and void** would have to be used.
I don't understand what you mean here.
If your "struct _class_SomeThing" would simply describe the same memory layout of classes that we have today, then no language change is necessary, it's purely a library solution. Well... maybe we'd need to add class postblits if we wanted copying (which can also be done by hand with a library "clone" function and a "special" static __postblit function). If not, then it gets complicated, as in order to retain an interface with C++ classes, D would either have to follow C++ ABI (he-he), or at the very least put the burden of mapping member function calls on the programmer.
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 16:52:17 UTC, Stanislav Blinov wrote:
 But structs in D have none of that.
Neither does C++ if you don't add a virtual function to it, so it would be the same. My question isn't whether structs have it now, but if the concept struct and class could be merged. Basically, the question is: are there features that are incompatible in terms of semantics? The class reference type should be fixable with a rewrite into templated smart pointers, so no need for big changes there, I think. The "new" construct would have to change a little bit so that it instantiates the pointed-to-type and not the reference-type.
 If your "struct _class_SomeThing" would simply describe the 
 same memory layout of classes that we have today, then no 
 language change is necessary, it's purely a library solution. 
 Well... maybe we'd need to add class postblits if we wanted 
 copying (which can also be done by hand with a library "clone" 
 function and a "special" static __postblit function).
Sure, D tries to stay compatible with C++, so that would dictate the memory layout.
 If not, then it gets complicated, as in order to retain an 
 interface with C++ classes, D would either have to follow C++ 
 ABI (he-he), or at the very least put the burden of mapping 
 member function calls on the programmer.
I thought D matched up to C++ ABI for structs/classes already (gdc vs g++, ldc vs clang)?
May 27 2017
next sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 27 May 2017 at 17:02:40 UTC, Ola Fosheim Grøstad 
wrote:

 The class reference type should be fixable with a rewrite into 
 templated smart pointers, so no need for big changes there, I 
 think.
Smart pointers impose a specific object lifetime, whereas (D) classes do not. You cannot lower (D) class instances to smart pointers.
May 27 2017
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 17:19:48 UTC, Moritz Maxeiner wrote:
 On Saturday, 27 May 2017 at 17:02:40 UTC, Ola Fosheim Grøstad 
 wrote:

 The class reference type should be fixable with a rewrite into 
 templated smart pointers, so no need for big changes there, I 
 think.
Smart pointers impose a specific object lifetime, whereas (D) classes do not. You cannot lower (D) class instances to smart pointers.
In this context smart pointers are just pointers that aren't raw pointers, e.g. alias this or something.
May 27 2017
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 27 May 2017 at 17:24:14 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 17:19:48 UTC, Moritz Maxeiner wrote:
 On Saturday, 27 May 2017 at 17:02:40 UTC, Ola Fosheim Grøstad 
 wrote:

 The class reference type should be fixable with a rewrite 
 into templated smart pointers, so no need for big changes 
 there, I think.
Smart pointers impose a specific object lifetime, whereas (D) classes do not. You cannot lower (D) class instances to smart pointers.
In this context smart pointers are just pointers that aren't raw pointers, e.g. alias this or something.
Then please don't call them "smart", because that term is specifically reserved for something that adds at least some additional features over a regular pointer (bounds checking, memory / lifetime management, etc.).
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 18:21:41 UTC, Moritz Maxeiner wrote:
 Then please don't call them "smart", because that term is 
 specifically reserved for something that adds at least some 
 additional features over a regular pointer (bounds checking, 
 memory / lifetime management, etc.).
"smart pointer" just means that it is a pointer wrapped in an ADT. In this context it could provide allocation-information would be one thing it could provide, or reference counting, member access or whatever. The "smart" part was deliberately left unspecified.
May 27 2017
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 27 May 2017 at 18:33:36 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 18:21:41 UTC, Moritz Maxeiner wrote:
 Then please don't call them "smart", because that term is 
 specifically reserved for something that adds at least some 
 additional features over a regular pointer (bounds checking, 
 memory / lifetime management, etc.).
"smart pointer" just means that it is a pointer wrapped in an ADT. In this context it could provide allocation-information would be one thing it could provide, or reference counting, member access or whatever. The "smart" part was deliberately left unspecified.
An ADT that adds features to the wrapped pointer; and if it adds features, it is not *just* a normal pointer anymore, i.e. you cannot use it as a verbatim replacement for normal class instances on the language level, because you change their semantics.
May 27 2017
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 17:19:48 UTC, Moritz Maxeiner wrote:
 On Saturday, 27 May 2017 at 17:02:40 UTC, Ola Fosheim Grøstad 
 wrote:

 The class reference type should be fixable with a rewrite into 
 templated smart pointers, so no need for big changes there, I 
 think.
Smart pointers impose a specific object lifetime, whereas (D) classes do not. You cannot lower (D) class instances to smart pointers.
Lower? No. Wrap - yes. With "scope" from DIP1000 you can even do it in a safe manner.
May 27 2017
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 27 May 2017 at 17:28:47 UTC, Stanislav Blinov wrote:
 On Saturday, 27 May 2017 at 17:19:48 UTC, Moritz Maxeiner wrote:
 On Saturday, 27 May 2017 at 17:02:40 UTC, Ola Fosheim Grøstad 
 wrote:

 The class reference type should be fixable with a rewrite 
 into templated smart pointers, so no need for big changes 
 there, I think.
Smart pointers impose a specific object lifetime, whereas (D) classes do not. You cannot lower (D) class instances to smart pointers.
Lower? No. Wrap - yes. With "scope" from DIP1000 you can even do it in a safe manner.
Maybe I was not clear: Of course you can put a class reference inside a struct, or even simulate a class using a rewriting mechanism, but you *cannot* use a smart pointer as a replacement for a class instance, because the latter is normal pointer, and the former adds features on top of a pointer; they cannot be the same as a matter of definition, i.e. you cannot replace classes with smart pointer structs on the language level, because it removes features from the language.
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 18:26:07 UTC, Moritz Maxeiner wrote:
 mechanism, but you *cannot*  use a smart pointer as a 
 replacement for a class instance, because the latter is normal 
 pointer, and the former adds features on top of a pointer; they 
 cannot be the same as a matter of definition, i.e. you cannot 
 replace classes with smart pointer structs on the language 
 level, because it removes features from the language.
I am not sure what you mean here. As long as the "smart pointer" is in a subtype relationship with the current "class reference" then it can add features, yes? You could do this as a compiler configuration even, switch out GC with ref-counting smart pointers. The point of this thread was to have fewer language constructs, with more lowering, so that the resulting language would be a super-language, that fully covers the original language (or close to it).
May 27 2017
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 27 May 2017 at 18:42:02 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 18:26:07 UTC, Moritz Maxeiner wrote:
 mechanism, but you *cannot*  use a smart pointer as a 
 replacement for a class instance, because the latter is normal 
 pointer, and the former adds features on top of a pointer; 
 they cannot be the same as a matter of definition, i.e. you 
 cannot replace classes with smart pointer structs on the 
 language level, because it removes features from the language.
I am not sure what you mean here. As long as the "smart pointer" is in a subtype relationship with the current "class reference" then it can add features, yes?
An example, then: --- module a; class Foo {} module b; import a; void bar(Foo foo) {} --- Here, `bar`, takes a (pointer to a) class instance as parameter `foo`. `foo` is a single pointer, i.e. 8 bytes on a 64bit OS, with *no* special semantics. You cannot replace the meaning of type `Foo` here with something that is not also exactly 8 bytes (on 64bit OS) with no special semantics, because that changes the semantics of `bar`. i.e. `Foo` must not be a smart pointer because a smart pointer necessarily introduces features (and thus changes the semantics). And this is exactly what you were proposing in the sentence I replied to; you were proposing to essentially change the semantics of every use of a class instance in all D code by rewriting `Foo` into a smart pointer.
 The point of this thread was to have fewer language constructs,
And my reply was "if you want to do this, it must use a normal pointer, not a smart pointer, because that changes semantics". If you want a smart pointer, use one, but don't suddenly make something that isn't a smart pointer by language design change shape into a smart pointer.
 with more lowering, so that the resulting language would be a 
 super-language, that fully covers the original language (or 
 close to it).
Sure, but then type `Foo` in the above must remain a normal pointer, not become a smart pointer.
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 19:01:12 UTC, Moritz Maxeiner wrote:
 Here, `bar`, takes a (pointer to a) class instance as parameter 
 `foo`. `foo` is a single pointer, i.e. 8 bytes on a 64bit OS, 
 with *no* special semantics.
Does the language spec say anything about the size of class references?
 If you want a smart pointer, use one, but don't suddenly make 
 something that isn't a smart pointer by language design change 
 shape into a smart pointer.
Is it specified? The common implementation uses a GC, but does it say that an implementation cannot use a reference counted smart pointer or a fat pointer instead?
 Sure, but then type `Foo` in the above must remain a normal 
 pointer, not become a smart pointer.
That really depends on the definition of the language.
May 27 2017
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 27 May 2017 at 19:26:50 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 19:01:12 UTC, Moritz Maxeiner wrote:
 Here, `bar`, takes a (pointer to a) class instance as 
 parameter `foo`. `foo` is a single pointer, i.e. 8 bytes on a 
 64bit OS, with *no* special semantics.
Does the language spec say anything about the size of class references?
Yes, is is defined as `ptrsize` and must have the exact same size as a pointer to a struct and - more importantly - a pointer to a stack frame[1].
 If you want a smart pointer, use one, but don't suddenly make 
 something that isn't a smart pointer by language design change 
 shape into a smart pointer.
Is it specified?
Yes, see above link. Unless you make *all* stack frame pointers smart pointers (which makes no sense whatsoever), class instances cannot be smart pointers in the language as it is specified right now.
 The common implementation uses a GC, but does it say that an 
 implementation cannot use a reference counted smart pointer or 
 a fat pointer instead?

 Sure, but then type `Foo` in the above must remain a normal 
 pointer, not become a smart pointer.
That really depends on the definition of the language.
Sure, and the definition requires it. [1] https://dlang.org/spec/abi.html#delegates
May 27 2017
next sibling parent Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
On Saturday, 27 May 2017 at 20:24:26 UTC, Moritz Maxeiner wrote:
 On Saturday, 27 May 2017 at 19:26:50 UTC, Ola Fosheim Grøstad 
 wrote:
 On Saturday, 27 May 2017 at 19:01:12 UTC, Moritz Maxeiner 
 wrote:
 Here, `bar`, takes a (pointer to a) class instance as 
 parameter `foo`. `foo` is a single pointer, i.e. 8 bytes on a 
 64bit OS, with *no* special semantics.
Does the language spec say anything about the size of class references?
Yes, is is defined as `ptrsize` and must have the exact same size as a pointer to a struct and - more importantly - a pointer to a stack frame[1].
Huh? You are talking about lambdas? Didnt find anything on class references in that Intel specific ABI, which appears to be optional anyway.
 Yes, see above link. Unless you make *all* stack frame pointers 
 smart pointers (which makes no sense whatsoever), class 
 instances cannot be smart pointers in the language as it is 
 specified right now.
I don't understand. Why are frame pointers relevant for class references?
 Sure, and the definition requires it.
Why?
May 27 2017
prev sibling parent Ola Fosheim Grostad <ola.fosheim.grostad gmail.com> writes:
On Saturday, 27 May 2017 at 20:24:26 UTC, Moritz Maxeiner wrote:
 Sure, and the definition requires it.

 [1] https://dlang.org/spec/abi.html#delegates
Please note that an ABI is an implementation specific linkage detail, it cannot be portable so it does not define language semantics.
May 27 2017
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 17:02:40 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 16:52:17 UTC, Stanislav Blinov 
 wrote:
 But structs in D have none of that.
Neither does C++ if you don't add a virtual function to it, so it would be the same. My question isn't whether structs have it now, but if the concept struct and class could be merged. Basically, the question is: are there features that are incompatible in terms of semantics?
But they are incompatible precisely because structs "don't have it". Inheritance for one. Reference semantics for another. A class reference is a pointer in disguise, struct is full layout on the stack. The only way to retain inheritance and reference semantics while removing "class" keyword would be not to merge classes into structs, but structs into classes. And then what, always allocate on the heap?
 The class reference type should be fixable with a rewrite into 
 templated smart pointers, so no need for big changes there, I 
 think. The "new" construct would have to change a little bit so 
 that it instantiates the pointed-to-type and not the 
 reference-type.
Which is all possible as a library with zero language changes. But for that to work, classes shall remain classes and structs shall remain structs.
 If your "struct _class_SomeThing" would simply describe the 
 same memory layout of classes that we have today, then no 
 language change is necessary, it's purely a library solution. 
 Well... maybe we'd need to add class postblits if we wanted 
 copying (which can also be done by hand with a library "clone" 
 function and a "special" static __postblit function).
Sure, D tries to stay compatible with C++, so that would dictate the memory layout.
 If not, then it gets complicated, as in order to retain an 
 interface with C++ classes, D would either have to follow C++ 
 ABI (he-he), or at the very least put the burden of mapping 
 member function calls on the programmer.
I thought D matched up to C++ ABI for structs/classes already (gdc vs g++, ldc vs clang)?
If that were true, we wouldn't even need the "extern(C++)", would we?
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 17:22:02 UTC, Stanislav Blinov wrote:
 But they are incompatible precisely because structs "don't have 
 it". Inheritance for one. Reference semantics for another. A 
 class reference is a pointer in disguise, struct is full layout 
 on the stack. The only way to retain inheritance and reference 
 semantics while removing "class" keyword would be not to merge 
 classes into structs, but structs into classes. And then what, 
 always allocate on the heap?
I don't understand this argument, why would this be more difficult for D than C++? You lower class into struct (with virtual, interfaces, whistles and bells) and retain reference semantics by making it unavailable for D-move-semantics.
 Which is all possible as a library with zero language changes. 
 But for that to work, classes shall remain classes and structs 
 shall remain structs.
Huh?
 If that were true, we wouldn't even need the "extern(C++)", 
 would we?
Sounds more like an implementation detail to me.
May 27 2017
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 17:30:49 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 17:22:02 UTC, Stanislav Blinov 
 wrote:
 But they are incompatible precisely because structs "don't 
 have it". Inheritance for one. Reference semantics for 
 another. A class reference is a pointer in disguise, struct is 
 full layout on the stack. The only way to retain inheritance 
 and reference semantics while removing "class" keyword would 
 be not to merge classes into structs, but structs into 
 classes. And then what, always allocate on the heap?
I don't understand this argument, why would this be more difficult for D than C++?
Perhaps it wouldn't be if we were talking about new language. With D, such a change falls out of "some language changes, a bit of automated source updating and a little bit of breakage", and becomes "whole language change, a rewrite of runtime and standard library, and breaking every single project that uses D today". Or did we leave behind your original question?
 Which is all possible as a library with zero language changes. 
 But for that to work, classes shall remain classes and structs 
 shall remain structs.
Huh?
Yes.
 If that were true, we wouldn't even need the "extern(C++)", 
 would we?
Sounds more like an implementation detail to me.
:) Everything is an "implementation detail".
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 18:06:11 UTC, Stanislav Blinov wrote:
 Perhaps it wouldn't be if we were talking about new language.
 With D, such a change falls out of "some language changes, a 
 bit of automated source updating and a little bit of breakage", 
 and becomes "whole language change, a rewrite of runtime and 
 standard library, and breaking every single project that uses D 
 today".
 Or did we leave behind your original question?
No. I am talking about language semantics. Are the semantics for class and struct conflicting or can they be merged? That is the question. I am talking about the language, as specified, not the implementation.
 Yes.
Huhhh?? :^)
 :) Everything is an "implementation detail".
No... No... No...
May 27 2017
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 18:13:52 UTC, Ola Fosheim Grøstad 
wrote:

 Or did we leave behind your original question?
No. I am talking about language semantics. Are the semantics for class and struct conflicting or can they be merged? That is the question. I am talking about the language, as specified, not the implementation.
Ahem. As specified, classes are reference types, struct aren't. What more is there to say?
May 27 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 18:44:03 UTC, Stanislav Blinov wrote:
 On Saturday, 27 May 2017 at 18:13:52 UTC, Ola Fosheim Grøstad 
 wrote:

 Or did we leave behind your original question?
No. I am talking about language semantics. Are the semantics for class and struct conflicting or can they be merged? That is the question. I am talking about the language, as specified, not the implementation.
Ahem. As specified, classes are reference types, struct aren't. What more is there to say?
Structs are reference types too. The specification is wrong.
May 27 2017
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 May 2017 at 18:44:42 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 27 May 2017 at 18:44:03 UTC, Stanislav Blinov 
 wrote:
 On Saturday, 27 May 2017 at 18:13:52 UTC, Ola Fosheim Grøstad 
 wrote:

 Or did we leave behind your original question?
No. I am talking about language semantics. Are the semantics for class and struct conflicting or can they be merged? That is the question. I am talking about the language, as specified, not the implementation.
Ahem. As specified, classes are reference types, struct aren't. What more is there to say?
Structs are reference types too. The specification is wrong.
I've seen this argument from you before, and it's incorrect. Structs may adopt reference semantics if they aggregate pointers, that's true. But they are not themselves reference types. Their representation is laid out inline. Classes, OTOH, are always references, to get at their memory you need an indirection. Thus, if we were to merge classes and structs, we'd have to pick one or the other.
May 27 2017
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Saturday, 27 May 2017 at 18:56:47 UTC, Stanislav Blinov wrote:
 I've seen this argument from you before, and it's incorrect. 
 Structs may adopt reference semantics if they aggregate 
 pointers, that's true. But they are not themselves reference 
 types. Their representation is laid out inline.
This is the ACID test: Values have no identity. An instance of a struct has an identity. Allocation is another issue. A stack allocation is just an optimization of a heap allocation. Many languages put all the activation records (stack frames) on the heap. This is very useful for high levels of concurrency.
 Classes, OTOH, are always references, to get at their memory 
 you need an indirection. Thus, if we were to merge classes and 
 structs, we'd have to pick one or the other.
Structs are more general, so you don't have to pick anything, you just add the class features to the struct. That means the minimal core language no longer have the class concept. The full language with lowering (syntactical sugar) still has the class concept since it can be covered by struct + "smart pointer" + modified new.
May 27 2017
prev sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 27 May 2017 at 20:13, Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Saturday, 27 May 2017 at 18:06:11 UTC, Stanislav Blinov wrote:
 Perhaps it wouldn't be if we were talking about new language.
 With D, such a change falls out of "some language changes, a bit of
 automated source updating and a little bit of breakage", and becomes "whole
 language change, a rewrite of runtime and standard library, and breaking
 every single project that uses D today".
 Or did we leave behind your original question?
No. I am talking about language semantics. Are the semantics for class and struct conflicting or can they be merged?
The semantic difference is that structs are POD records, and classes are references (or pointers) to GC heap with inheritance (underlying record includes fields from base classes). For ABI, structs are compatible with C (this is documented as per spec), and classes underlying records are compatible with C++ (don't think this is documented, but it's certainly assumed). Focusing on the latter point, this means that the following declarations: struct Something { int a; long b; char c; } class Something { int a; long b; char c; } are identical to each other, apart from the latter getting a __vptr and __monitor field. However, for extern(D) classes, there's actually nothing stopping a D compiler implementer from making class types more memory efficient, an optimizing compiler could decide to re-arrange class fields as: class Something { long b; int a; char c; } After all, we only need extern(D) to be compatible with ourselves, not other languages. As a side note, when I talked about D at the GNU Hackers Meeting a number of years back, when I said that structs and classes are two distinct types - one being POD-only, the other being a reference that comes with the bells and whistles of OOP - I actually got a small cheer. This gives me a very strong impression of what C++ programmers think of their own situation regarding struct vs class, and that we should not be so eager to follow their design.
May 28 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Sunday, 28 May 2017 at 09:09:39 UTC, Iain Buclaw wrote:
 However, for extern(D) classes, there's actually nothing 
 stopping a D compiler implementer from making class types more 
 memory efficient, an optimizing compiler could decide to 
 re-arrange class fields as:

     class Something
     {
         long b;
         int a;
         char c;
     }
Yes, but you could do that for structs as well, after static analysis establishing that it no code in this specific program is making assumptions about layout. Or you could have an attribute that says that that field X should be at byte-offset N, but all other fields can move.
 As a side note, when I talked about D at the GNU Hackers 
 Meeting a number of years back, when I said that structs and 
 classes are two distinct types - one being POD-only, the other 
 being a reference that comes with the bells and whistles of OOP 
 - I actually got a small cheer.  This gives me a very strong 
 impression of what C++ programmers think of their own situation 
 regarding struct vs class, and that we should not be so eager 
 to follow their design.
Did they explain why? Many other languages provide a single construct with far more wide-ranging features than D/C++. For generic programming it is generally better to have fewer constructs, but you might need a way convenient way to express constraints (i.e. C++ concepts).
May 28 2017
parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 28 May 2017 at 13:30, Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, 28 May 2017 at 09:09:39 UTC, Iain Buclaw wrote:
 However, for extern(D) classes, there's actually nothing stopping a D
 compiler implementer from making class types more memory efficient, an
 optimizing compiler could decide to re-arrange class fields as:

     class Something
     {
         long b;
         int a;
         char c;
     }
Yes, but you could do that for structs as well, after static analysis establishing that it no code in this specific program is making assumptions about layout. Or you could have an attribute that says that that field X should be at byte-offset N, but all other fields can move.
 As a side note, when I talked about D at the GNU Hackers Meeting a number
 of years back, when I said that structs and classes are two distinct types -
 one being POD-only, the other being a reference that comes with the bells
 and whistles of OOP - I actually got a small cheer.  This gives me a very
 strong impression of what C++ programmers think of their own situation
 regarding struct vs class, and that we should not be so eager to follow
 their design.
Did they explain why? Many other languages provide a single construct with far more wide-ranging features than D/C++.
I said it all in one breath, so you could leave it up to interpretation whether they applauded the fact that there is a separation in semantics, or whether there is no multiple inheritance in D (except via interfaces). When asking one person over dinner later about what they felt was wrong about struct/class in C++, I got the impression that because there's almost no distinction between the two, class seems more like a misfeature of C++. You could say that C++ should have stuck to one type, instead of having two. And because in D we make a very clear distinction, that justifies the reason to have both struct and class.
May 28 2017
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Sunday, 28 May 2017 at 12:31:35 UTC, Iain Buclaw wrote:
 I said it all in one breath, so you could leave it up to 
 interpretation whether they applauded the fact that there is a 
 separation in semantics, or whether there is no multiple 
 inheritance in D (except via interfaces).

 When asking one person over dinner later about what they felt 
 was wrong about struct/class in C++, I got the impression that 
 because there's almost no distinction between the two, class 
 seems more like a misfeature of C++.
Well, class and struct is semantically the same in C++. The only difference is that you don't have private and protected on structs. So the distinction is historical, to quote cppreference.com: «The keywords are identical except for the default member access and the default base class access.»
 You could say that C++ should have stuck to one type, instead 
 of having two.
Struct and class is one type in C++. The difference is in the syntax where the grammar does not allow access protection for the struct keyword. So not semantical, but syntactical.
 And because in D we make a very clear distinction, that 
 justifies the reason to have both struct and class.
But you don't make a very clear distinction in D. If struct was a pure value type and mapped to pure valued tuples, then you might have a justification for it. From a type-system point of view the distinction makes no sense to me.
May 28 2017
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Sunday, 28 May 2017 at 14:30:00 UTC, Ola Fosheim Grøstad wrote:
 Struct and class is one type in C++. The difference is in the 
 syntax where the grammar does not allow access protection for 
 the struct keyword. So not semantical, but syntactical.
I.e. you can just search-and-replace "struct" with "class" in C++ and it will behave the same way. "struct" is only used as a mnemonic device...
May 28 2017
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Saturday, May 27, 2017 16:37:04 Ola Fosheim Grøstad via Digitalmars-d 
wrote:
 Monitor (i.e. for "synchronized") and
Wasn't this going to be removed?
There was definitely talk of doing it, but it's never actually happened. I don't think that it was actually decided that we would though, and some other things that we _definitely_ decided we do have never actually happened either (e.g. remove delete from the language and remove toString, toHash, opCmp, and opEquals from Object). Getting major changes in is often something that doesn't work out very well given the obstacles involved. I don't recall what the obstacles to getting the monitor changes in where, but I suspect that in order to get them in, someone would effectively have to champion the changes and push them through, and while I think that there was someone trying to do that at one point, they seem to have given up on it. I don't know if they ran into insurmountable problems or simply gave up and left. But as long as D classes have a built-in monitor, then that's one of the key differences between a D class or struct (or a D and C++ class for that matter). - Jonathan M Davis
May 27 2017
prev sibling parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 27 May 2017 at 20:34, Jonathan M Davis via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Saturday, May 27, 2017 16:37:04 Ola Fosheim Grøstad via Digitalmars-d
 wrote:
 Monitor (i.e. for "synchronized") and
Wasn't this going to be removed?
There was definitely talk of doing it, but it's never actually happened. I don't think that it was actually decided that we would though, and some other things that we _definitely_ decided we do have never actually happened either (e.g. remove delete from the language and remove toString, toHash, opCmp, and opEquals from Object). Getting major changes in is often something that doesn't work out very well given the obstacles involved.
There's nothing blocking the deprecation of monitors. Just someone needs to do the work.
May 28 2017
prev sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 27 May 2017 at 16:12, Ola Fosheim Grøstad via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 I wonder, what would break if all the features of class was merged into
 struct?

 Imagine that:

     class Something ... { ... }

 is lowered into:

     struct _class_Something ... { ... }
     alias Something = MagicClassRef!_class_Something;

 Is it conceivable with some language changes, a bit of automated source
 updating and a little bit of breakage?
Strictly speaking, this already is the case. Something sth = new Something (...); all that is really doing is just: struct Something* sth = new Something (...); You just aren't exposed this in the language.
May 28 2017
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Sunday, 28 May 2017 at 08:24:50 UTC, Iain Buclaw wrote:
 Strictly speaking, this already is the case.

     Something sth = new Something (...);

 all that is really doing is just:

     struct Something* sth = new Something (...);

 You just aren't exposed this in the language.
Right, but since the language now is more powerful than it was in D1, it should be possible to implement class references as a templated struct, right? So there is no longer a need for this special casing of class vs struct. The only thing you need to do is modify "new" to recognize it. I think?
May 28 2017