www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - -betterC and extern(C++) classes

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
I was experimenting with -betterC and found out that C++ classes 
doesn't work. Because the resulting object file needs a symbol 
"_D14TypeInfo_Class6__vtblZ" which is in druntime. I suppose this 
is to support T.classinfo?

Could we remove T.classinfo and make classes work under -betterC? 
Or is there some other reason preventing this from happening?

Thanks.
Sep 10
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 10/09/2017 9:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ classes doesn't 
 work. Because the resulting object file needs a symbol 
 "_D14TypeInfo_Class6__vtblZ" which is in druntime. I suppose this is to 
 support T.classinfo?
Nope.
 Could we remove T.classinfo and make classes work under -betterC? Or is 
 there some other reason preventing this from happening?
 
 Thanks.
Definitely not. Classes require vtable's to work. Vtables are generated as part of TypeInfo. No TypeInfo, no classes, simple to understand. Same reason why you can't use classes and cross the dll boundary on Windows. But if you prefer not having any methods to call, then I'm sure we can remove the requirement on the vtable ;) (Not a solution)
Sep 10
next sibling parent reply 9il <ilyayaroshenko gmail.com> writes:
On Sunday, 10 September 2017 at 08:56:11 UTC, rikki cattermole 
wrote:
 On 10/09/2017 9:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ 
 classes doesn't work. Because the resulting object file needs 
 a symbol "_D14TypeInfo_Class6__vtblZ" which is in druntime. I 
 suppose this is to support T.classinfo?
Nope.
 Could we remove T.classinfo and make classes work under 
 -betterC? Or is there some other reason preventing this from 
 happening?
 
 Thanks.
Definitely not. Classes require vtable's to work. Vtables are generated as part of TypeInfo. No TypeInfo, no classes, simple to understand.
No. vtables can be generated without RTTI and we can have both D and C++ classes in betterC mode. It may not be ready now, but it is definitely possible and should be supported. Best reagards, Ilya
Sep 10
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 10/09/2017 10:03 AM, 9il wrote:
 On Sunday, 10 September 2017 at 08:56:11 UTC, rikki cattermole wrote:
 On 10/09/2017 9:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ classes 
 doesn't work. Because the resulting object file needs a symbol 
 "_D14TypeInfo_Class6__vtblZ" which is in druntime. I suppose this is 
 to support T.classinfo?
Nope.
 Could we remove T.classinfo and make classes work under -betterC? Or 
 is there some other reason preventing this from happening?

 Thanks.
Definitely not. Classes require vtable's to work. Vtables are generated as part of TypeInfo. No TypeInfo, no classes, simple to understand.
No. vtables can be generated without RTTI and we can have both D and C++ classes in betterC mode. It may not be ready now, but it is definitely possible and should be supported. Best reagards, Ilya
Agreed, but that is a bigger change and would require a bit more of a rethink than just a simple 'remove reference to symbol'.
Sep 10
prev sibling parent Paulo Pinto <pjmlp progtools.org> writes:
On Sunday, 10 September 2017 at 08:56:11 UTC, rikki cattermole 
wrote:
 On 10/09/2017 9:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ 
 classes doesn't work. Because the resulting object file needs 
 a symbol "_D14TypeInfo_Class6__vtblZ" which is in druntime. I 
 suppose this is to support T.classinfo?
Nope.
 Could we remove T.classinfo and make classes work under 
 -betterC? Or is there some other reason preventing this from 
 happening?
 
 Thanks.
Definitely not. Classes require vtable's to work. Vtables are generated as part of TypeInfo. No TypeInfo, no classes, simple to understand. Same reason why you can't use classes and cross the dll boundary on Windows. ....
You sure can do that in C++, since Windows 3.x days. The constraint is that C++ compiler needs to be the same on both sides. Then there is COM as language neutral vtable.
Sep 10
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/10/2017 1:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ classes doesn't work. 
 Because the resulting object file needs a symbol "_D14TypeInfo_Class6__vtblZ" 
 which is in druntime. I suppose this is to support T.classinfo?
 
 Could we remove T.classinfo and make classes work under -betterC? Or is there 
 some other reason preventing this from happening?
Yes, we do want to move towards "Better C++" working in an analogous manner, and that means removing the typeinfo dependency.
Sep 10
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 10 September 2017 at 09:31:55 UTC, Walter Bright wrote:
 Yes, we do want to move towards "Better C++" working in an 
 analogous manner, and that means removing the typeinfo 
 dependency.
TypeInfo is cheap and useful with classes. You shouldn't be removing it, just stripping it to the minimum needed so the rest is opt in.
Sep 10
prev sibling next sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 10 September 2017 at 09:31:55 UTC, Walter Bright wrote:
 On 9/10/2017 1:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ 
 classes doesn't work. Because the resulting object file needs 
 a symbol "_D14TypeInfo_Class6__vtblZ" which is in druntime. I 
 suppose this is to support T.classinfo?
 
 Could we remove T.classinfo and make classes work under 
 -betterC? Or is there some other reason preventing this from 
 happening?
Yes, we do want to move towards "Better C++" working in an analogous manner, and that means removing the typeinfo dependency.
If TypeInfo for extern(C++) classes is removed, couldn't final extern(C++) classes without base class and which don't implement any interfaces omit the vtable so that the following assert holds: --- final extern(C++) class Foo {} static assert (__traits(classInstanceSize, Foo) == 0LU); --- The reason I ask is that fairly often I have an abstraction that's better suited as a reference type than a value type, but doesn't need any runtime polymorphy (or the monitor standard classes have). Structs + pointers are the only way I know of to avoid the (in this special case) unneeded vtable overhead, but it always ends up looking worse to read.
Sep 10
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
 If TypeInfo for extern(C++) classes is removed, couldn't final 
 extern(C++) classes without base class and which don't implement any 
 interfaces omit the vtable so that the following assert holds:
 
 ---
 final extern(C++) class Foo {}
 static assert (__traits(classInstanceSize, Foo) == 0LU);
 ---
 
 The reason I ask is that fairly often I have an abstraction that's 
 better suited as a reference type than a value type, but doesn't need 
 any runtime polymorphy (or the monitor standard classes have). Structs + 
 pointers are the only way I know of to avoid the (in this special case) 
 unneeded vtable overhead, but it always ends up looking worse to read.
We can do it for any class if its final. The problem isn't generating the vtable's. But the information required for casting.
Sep 10
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 10 September 2017 at 14:04:20 UTC, rikki cattermole 
wrote:
 On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
 If TypeInfo for extern(C++) classes is removed, couldn't final 
 extern(C++) classes without base class and which don't 
 implement any interfaces omit the vtable so that the following 
 assert holds:
 
 ---
 final extern(C++) class Foo {}
 static assert (__traits(classInstanceSize, Foo) == 0LU);
 ---
 
 The reason I ask is that fairly often I have an abstraction 
 that's better suited as a reference type than a value type, 
 but doesn't need any runtime polymorphy (or the monitor 
 standard classes have). Structs + pointers are the only way I 
 know of to avoid the (in this special case) unneeded vtable 
 overhead, but it always ends up looking worse to read.
We can do it for any class if its final.
Even final classes can always inherit (potentially already overridden) virtual methods from their parent classes and since all normal D classes inherit from core.object : Object [1], which defines virtual methods (`toString`, `toHash`, `opCmp, and `opEquals`), I don't see how this can be true.
 The problem isn't generating the vtable's. But the information 
 required for casting.
This applies to normal D classes, but D doesn't support (dynamic) casts for extern(C++) classes, anyway, so this shouldn't be an issue for them. [1] https://github.com/somzzz/druntime/blob/74882c8a48dd8a827181e3b89c4f0f205c881ac5/src/object.d#L50
Sep 10
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Sunday, 10 September 2017 at 14:42:42 UTC, Moritz Maxeiner 
wrote:
 On Sunday, 10 September 2017 at 14:04:20 UTC, rikki cattermole 
 wrote:
 On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
 If TypeInfo for extern(C++) classes is removed, couldn't 
 final extern(C++) classes without base class and which don't 
 implement any interfaces omit the vtable so that the 
 following assert holds:
 
 ---
 final extern(C++) class Foo {}
 static assert (__traits(classInstanceSize, Foo) == 0LU);
 ---
 
 The reason I ask is that fairly often I have an abstraction 
 that's better suited as a reference type than a value type, 
 but doesn't need any runtime polymorphy (or the monitor 
 standard classes have). Structs + pointers are the only way I 
 know of to avoid the (in this special case) unneeded vtable 
 overhead, but it always ends up looking worse to read.
We can do it for any class if its final.
Even final classes can always inherit (potentially already overridden) virtual methods from their parent classes and since all normal D classes inherit from core.object : Object [1], which defines virtual methods (`toString`, `toHash`, `opCmp, and `opEquals`), I don't see how this can be true.
With a final class reference, we always know what function to call at compile time (since it can't be inherited). Therefore we don't need a vtable.
 The problem isn't generating the vtable's. But the information 
 required for casting.
This applies to normal D classes, but D doesn't support (dynamic) casts for extern(C++) classes, anyway, so this shouldn't be an issue for them. [1] https://github.com/somzzz/druntime/blob/74882c8a48dd8a827181e3b89c4f0f205c881ac5/src/object.d#L50
Sep 10
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 10 September 2017 at 15:12:12 UTC, Yuxuan Shui wrote:
 On Sunday, 10 September 2017 at 14:42:42 UTC, Moritz Maxeiner 
 wrote:
 On Sunday, 10 September 2017 at 14:04:20 UTC, rikki cattermole 
 wrote:
 On 10/09/2017 2:19 PM, Moritz Maxeiner wrote:
 If TypeInfo for extern(C++) classes is removed, couldn't 
 final extern(C++) classes without base class and which don't 
 implement any interfaces omit the vtable so that the 
 following assert holds:
 
 ---
 final extern(C++) class Foo {}
 static assert (__traits(classInstanceSize, Foo) == 0LU);
 ---
 
 The reason I ask is that fairly often I have an abstraction 
 that's better suited as a reference type than a value type, 
 but doesn't need any runtime polymorphy (or the monitor 
 standard classes have). Structs + pointers are the only way 
 I know of to avoid the (in this special case) unneeded 
 vtable overhead, but it always ends up looking worse to read.
We can do it for any class if its final.
Even final classes can always inherit (potentially already overridden) virtual methods from their parent classes and since all normal D classes inherit from core.object : Object [1], which defines virtual methods (`toString`, `toHash`, `opCmp, and `opEquals`), I don't see how this can be true.
With a final class reference, we always know what function to call at compile time (since it can't be inherited). Therefore we don't need a vtable.
--- class Base { string name() { return "Base"; } } class ChildA : Base { override string name() { return "ChildA"; } } final class ChildB : Base { override string name() { return "ChildB"; } } void foo(Base b) { import std.stdio; b.name.writeln; } void main(string[] args) { Base b; if (args.length > 1) b = new ChildA; else b = new ChildB; b.foo(); } --- It is not known at compile time which class `foo`'s parameter `b` will actually be an instance of (Base, ChildA, or ChildB), so static dispatch is not possible; it requires dynamic dispatch. Since dynamic dispatch for classes is done in D via vtables, ChildB needs a vtable.
Sep 10
prev sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Sunday, 10 September 2017 at 09:31:55 UTC, Walter Bright wrote:
 On 9/10/2017 1:40 AM, Yuxuan Shui wrote:
 I was experimenting with -betterC and found out that C++ 
 classes doesn't work. Because the resulting object file needs 
 a symbol "_D14TypeInfo_Class6__vtblZ" which is in druntime. I 
 suppose this is to support T.classinfo?
 
 Could we remove T.classinfo and make classes work under 
 -betterC? Or is there some other reason preventing this from 
 happening?
Yes, we do want to move towards "Better C++" working in an analogous manner, and that means removing the typeinfo dependency.
Is there a plan? Are there any simple tasks I can take/help?
Sep 10
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/10/2017 7:01 AM, Yuxuan Shui wrote:
 Is there a plan? Are there any simple tasks I can take/help?
I filed an enhancement request: https://issues.dlang.org/show_bug.cgi?id=17822 The rest is kinda up to me.
Sep 10
prev sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
By the way, can we dynamic_cast extern(C++) classes in C++? If 
not, what are we generating these TypeInfo_Class for?
Sep 10
next sibling parent Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 10 September 2017 at 15:08:50 UTC, Yuxuan Shui wrote:
 By the way, can we dynamic_cast extern(C++) classes in C++?
It doesn't work for me OOTB with dmd 2.075, at least (though I may be missing something): --- classes.d --- import core.memory; extern(C++) class Parent { char id() { return 'P'; } } extern(C++) class Child : Parent { override char id() { return 'C'; } } extern(C++) Parent makeParent() { auto p = new Parent; GC.addRoot(cast(void*) p); return p; } extern(C++) Child makeChild() { auto c = new Child; GC.addRoot(cast(void*) c); return c; } extern(C++) void releaseParent(Parent p) { GC.removeRoot(cast(void*) p); } extern(C++) void releaseChild(Child c) { GC.removeRoot(cast(void*) c); } ----------------- --- main.cc --- #include <iostream> class Parent { public: virtual char id(); }; class Child : public Parent { }; extern Parent* makeParent(); extern Child* makeChild(); extern void releaseParent(Parent* p); extern void releaseChild(Child* c); extern "C" void rt_init(); extern "C" void rt_term(); bool isChild(Parent* p) { return nullptr != dynamic_cast<Child*>(p); } int main(int argc, char** argv) { rt_init(); Parent* p = makeParent(); Child* c = makeChild(); std::cout << p->id() << "\n"; std::cout << c->id() << "\n"; std::cout << "identifier\tChild\n"; std::cout << "p\t" << isChild(p) << "\t"; std::cout << "c\t" << isChild(c) << "\t"; releaseChild(c); releaseParent(p); rt_term(); return 0; } --------------- --- Compile&Link --- $ dmd -c classes.d $ g++ -std=c++11 -o main main.cc classes.o -L/path/to/dmd-2.075/lib64/ -lphobos2 /tmp/ccwjJ9Xe.o: In function `isChild(Parent*)': main.cc:(.text+0x20): undefined reference to `typeinfo for Parent' /tmp/ccwjJ9Xe.o:(.rodata._ZTI5Child[_ZTI5Child]+0x10): undefined reference to `typeinfo for Parent' collect2: error: ld returned 1 exit status --------------------
Sep 10
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/10/2017 8:08 AM, Yuxuan Shui wrote:
 By the way, can we dynamic_cast extern(C++) classes in C++?
No. Generally, one would need C++ RTTI for that to work, and that: 1. is specific to the particular C++ compiler 2. is undocumented, half-documented, or wrongly documented 3. requires the C++ runtime library to work It's certainly possible to do this, but requires time, effort, and a certain willingness to deal with the dirty underbelly of undocumented binary formats.
 If not, what are we generating these TypeInfo_Class for?
It has other uses, such as providing info for associative arrays and the garbage collector.
Sep 10