digitalmars.D - Fun with extern(C++)
- Manu via Digitalmars-d (22/22) Jan 26 2016 Okay, new issues:
- Jacob Carlborg (18/20) Jan 26 2016 No that I know how the C++ compatibility works but I would guess the
- Steven Schveighoffer (6/24) Jan 26 2016 The short answer to this question is, no you cannot. The layouts are
- Manu via Digitalmars-d (5/37) Jan 26 2016 Interface is just a vtable... what makes the layout different?
- Steven Schveighoffer (10/48) Jan 26 2016 I believe the D interface mechanism depends on the vtable layout being a...
- Manu via Digitalmars-d (6/24) Jan 26 2016 I'm not sure there's a difference in the calling convention... the
- Jacob Carlborg (4/8) Jan 26 2016 Isn't the layout of the vtables different?
- Manu via Digitalmars-d (9/15) Jan 26 2016 Probably, but the layout of the vtable is defined by the interface,
- Benjamin Thaut (9/20) Jan 26 2016 For a C++ class the first entry in the vtable is actually the
- Igor (5/28) Jan 26 2016 Why couldn't D have been designed to extend the C++ class layout
- Kagamin (3/10) Jan 26 2016 D classes are derived from Object class.
- Manu via Digitalmars-d (10/19) Jan 26 2016 How does that work?
- Kagamin (5/13) Jan 26 2016 Interface vtable has a fixup, which added to the interface
- Steven Schveighoffer (3/8) Jan 26 2016 Technically, D interfaces only EXPLICITLY cast to Object.
- Elie Morisse (16/28) Jan 26 2016 It helps that Object is a just a handful of virtual methods.
- Manu via Digitalmars-d (14/31) Jan 26 2016 implemented by a C++ class, it still needs to be able to cast to Object,
- Walter Bright (10/10) Jan 26 2016 To understand this you have to step back and understand what interfaces ...
Okay, new issues: extern(C++) class Base {} class Derived : Base {} It seems that 'Derived' is implicitly a C++ class... I guess that seems okay, but this leads to a series of edges where things start breaking down... pragma(msg, BaseClassesTuple!Derived); -> Error: tuple index 0 exceeds 0 Okay... that's broken. But I need to know it's base class. pragma(msg, BaseTypeTuple!ComponentType); -> (in Base) Base is reported as an interface? That's weird... and get's me wondering: interface Iface {} class Derived2 : Base, Iface {} -> Error: C++ class 'Derived2' cannot implement D interface 'Iface' Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface? Users will need to declare extern(C++) interfaces anytime they want to use it on any class with a C++ base class? I kinda hoped that having a C++ class at the bottom of the stack would just be a detail once D classes are derived from it, but it seems that any class derived from a C++ base is placed into a separate world. At very least, I need BaseClassesTuple to work with C++ classes. I suspect this is probably fixable?
Jan 26 2016
On 2016-01-26 13:59, Manu via Digitalmars-d wrote:Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?No that I know how the C++ compatibility works but I would guess the compiler needs to know at compile time how to call a method. If it would be possible to implement a D interface as either a D class or C++ class. The compiler cannot know which runtime type a variable which is declared as an interface can hold. interface A { void foo(); } class B : A { void foo(); } extern(C++) class C : A { void foo(); } // assuming this works A a = new B; A b = new C; // assuming this works a.foo(); b.foo(); When the compiler sees "a" or "b", how should it know it should call "foo" as a D method or C++ method? It only knows about the static type which is A, a D interface. -- /Jacob Carlborg
Jan 26 2016
On 1/26/16 8:58 AM, Jacob Carlborg wrote:On 2016-01-26 13:59, Manu via Digitalmars-d wrote:The short answer to this question is, no you cannot. The layouts are different. It's why I have always said, D interfaces should implicitly convert to Object and support all Object methods. Only D classes can implement D interfaces. -SteveHmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?No that I know how the C++ compatibility works but I would guess the compiler needs to know at compile time how to call a method. If it would be possible to implement a D interface as either a D class or C++ class. The compiler cannot know which runtime type a variable which is declared as an interface can hold. interface A { void foo(); } class B : A { void foo(); } extern(C++) class C : A { void foo(); } // assuming this works A a = new B; A b = new C; // assuming this works a.foo(); b.foo(); When the compiler sees "a" or "b", how should it know it should call "foo" as a D method or C++ method? It only knows about the static type which is A, a D interface.
Jan 26 2016
On 27 January 2016 at 01:38, Steven Schveighoffer via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 1/26/16 8:58 AM, Jacob Carlborg wrote:Interface is just a vtable... what makes the layout different? Surely any class can take a vtable definition and populate it with some function pointers.On 2016-01-26 13:59, Manu via Digitalmars-d wrote:The short answer to this question is, no you cannot. The layouts are different. It's why I have always said, D interfaces should implicitly convert to Object and support all Object methods. Only D classes can implement D interfaces.Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?No that I know how the C++ compatibility works but I would guess the compiler needs to know at compile time how to call a method. If it would be possible to implement a D interface as either a D class or C++ class. The compiler cannot know which runtime type a variable which is declared as an interface can hold. interface A { void foo(); } class B : A { void foo(); } extern(C++) class C : A { void foo(); } // assuming this works A a = new B; A b = new C; // assuming this works a.foo(); b.foo(); When the compiler sees "a" or "b", how should it know it should call "foo" as a D method or C++ method? It only knows about the static type which is A, a D interface.
Jan 26 2016
On 1/26/16 10:57 AM, Manu via Digitalmars-d wrote:On 27 January 2016 at 01:38, Steven Schveighoffer via Digitalmars-d <digitalmars-d puremagic.com> wrote:I believe the D interface mechanism depends on the vtable layout being a certain way in the object. The C++ layout conflicts with that. I could imagine one could construct an appropriate TypeInfo pointer inside the C++ class, with the proper offset stored in a mock TypeInfo class, such that you could actually get the virtual function to call. But you would run into other problems. For example, if you wanted to cast to another interface, you would likely segfault. This would be a nightmare to do in a library. -SteveOn 1/26/16 8:58 AM, Jacob Carlborg wrote:Interface is just a vtable... what makes the layout different? Surely any class can take a vtable definition and populate it with some function pointers.On 2016-01-26 13:59, Manu via Digitalmars-d wrote:The short answer to this question is, no you cannot. The layouts are different. It's why I have always said, D interfaces should implicitly convert to Object and support all Object methods. Only D classes can implement D interfaces.Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?No that I know how the C++ compatibility works but I would guess the compiler needs to know at compile time how to call a method. If it would be possible to implement a D interface as either a D class or C++ class. The compiler cannot know which runtime type a variable which is declared as an interface can hold. interface A { void foo(); } class B : A { void foo(); } extern(C++) class C : A { void foo(); } // assuming this works A a = new B; A b = new C; // assuming this works a.foo(); b.foo(); When the compiler sees "a" or "b", how should it know it should call "foo" as a D method or C++ method? It only knows about the static type which is A, a D interface.
Jan 26 2016
On 26 January 2016 at 23:58, Jacob Carlborg via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 2016-01-26 13:59, Manu via Digitalmars-d wrote:I'm not sure there's a difference in the calling convention... the function being called may perform adjustment of the 'this' pointer such that it's correct relative to the class that implemented the function, but that's internal to the function being called.Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?No that I know how the C++ compatibility works but I would guess the compiler needs to know at compile time how to call a method. If it would be possible to implement a D interface as either a D class or C++ class. The compiler cannot know which runtime type a variable which is declared as an interface can hold. interface A { void foo(); } class B : A { void foo(); } extern(C++) class C : A { void foo(); } // assuming this works A a = new B; A b = new C; // assuming this works a.foo(); b.foo(); When the compiler sees "a" or "b", how should it know it should call "foo" as a D method or C++ method? It only knows about the static type which is A, a D interface.
Jan 26 2016
On 2016-01-26 16:49, Manu via Digitalmars-d wrote:I'm not sure there's a difference in the calling convention... the function being called may perform adjustment of the 'this' pointer such that it's correct relative to the class that implemented the function, but that's internal to the function being called.Isn't the layout of the vtables different? -- /Jacob Carlborg
Jan 26 2016
On 27 January 2016 at 02:01, Jacob Carlborg via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 2016-01-26 16:49, Manu via Digitalmars-d wrote:Probably, but the layout of the vtable is defined by the interface, and the interface type is always known, so I don't see why there should be any problem. Whether it's extern(C++) or extern(D), the class populating the vtable with functions knows the layout. I think it all comes down to this conversion to Object thing. If an interface must do that, then that's probably an issue without jamming an Object instance in the class somewhere.I'm not sure there's a difference in the calling convention... the function being called may perform adjustment of the 'this' pointer such that it's correct relative to the class that implemented the function, but that's internal to the function being called.Isn't the layout of the vtables different?
Jan 26 2016
On Tuesday, 26 January 2016 at 16:13:55 UTC, Manu wrote:Probably, but the layout of the vtable is defined by the interface, and the interface type is always known, so I don't see why there should be any problem. Whether it's extern(C++) or extern(D), the class populating the vtable with functions knows the layout. I think it all comes down to this conversion to Object thing. If an interface must do that, then that's probably an issue without jamming an Object instance in the class somewhere.For a C++ class the first entry in the vtable is actually the first virtual function. (usually the destructor). For a D class the first entry in the vtable is the classinfo. Thus the problem if you derive a D class from a extern(C++) base class. I don't see any way to actually fix this, adjusting the this pointer won't help. Once you derive a D class from a extern(C++) base class it is no longer a fully functional D class. For example monitor (e.g. synchronized methods) won't work.
Jan 26 2016
On Tuesday, 26 January 2016 at 16:25:35 UTC, Benjamin Thaut wrote:On Tuesday, 26 January 2016 at 16:13:55 UTC, Manu wrote:Why couldn't D have been designed to extend the C++ class layout with the vtable at the start and the new stuff at the bottom? Would that have worked? If so, why not allow for a new class layout like "extern(C++) class X { }"Probably, but the layout of the vtable is defined by the interface, and the interface type is always known, so I don't see why there should be any problem. Whether it's extern(C++) or extern(D), the class populating the vtable with functions knows the layout. I think it all comes down to this conversion to Object thing. If an interface must do that, then that's probably an issue without jamming an Object instance in the class somewhere.For a C++ class the first entry in the vtable is actually the first virtual function. (usually the destructor). For a D class the first entry in the vtable is the classinfo. Thus the problem if you derive a D class from a extern(C++) base class. I don't see any way to actually fix this, adjusting the this pointer won't help. Once you derive a D class from a extern(C++) base class it is no longer a fully functional D class. For example monitor (e.g. synchronized methods) won't work.
Jan 26 2016
On Tuesday, 26 January 2016 at 12:59:35 UTC, Manu wrote:Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?D interfaces are implicitly convertible to Object.I kinda hoped that having a C++ class at the bottom of the stack would just be a detail once D classes are derived from it, but it seems that any class derived from a C++ base is placed into a separate world.D classes are derived from Object class.
Jan 26 2016
On 27 January 2016 at 00:37, Kagamin via Digitalmars-d <digitalmars-d puremagic.com> wrote:On Tuesday, 26 January 2016 at 12:59:35 UTC, Manu wrote:How does that work? I've never really used classes in D.Hmmm. I wonder if this will cause problems... Is it impossible to support a C++ class implementing a D interface?D interfaces are implicitly convertible to Object.So, you're saying that if you have an 'I' pointer, which may be implemented by a C++ class, it still needs to be able to cast to Object, and therefore fails? I wonder if a C++ class could somehow be promoted to a D class when being derived in D, by having an Object placed somewhere. 'this' adjustment might be required at that point though, and that's not really nice in C++.I kinda hoped that having a C++ class at the bottom of the stack would just be a detail once D classes are derived from it, but it seems that any class derived from a C++ base is placed into a separate world.D classes are derived from Object class.
Jan 26 2016
On Tuesday, 26 January 2016 at 15:53:39 UTC, Manu wrote:How does that work? I've never really used classes in D.Interface vtable has a fixup, which added to the interface pointer gives object pointer.I mean if you want to derive from two classes, that sounds nasty :)D classes are derived from Object class.So, you're saying that if you have an 'I' pointer, which may be implemented by a C++ class, it still needs to be able to cast to Object, and therefore fails? I wonder if a C++ class could somehow be promoted to a D class when being derived in D, by having an Object placed somewhere.
Jan 26 2016
On 1/26/16 12:08 PM, Kagamin wrote:On Tuesday, 26 January 2016 at 15:53:39 UTC, Manu wrote:Technically, D interfaces only EXPLICITLY cast to Object. -SteveHow does that work? I've never really used classes in D.Interface vtable has a fixup, which added to the interface pointer gives object pointer.
Jan 26 2016
On Tuesday, 26 January 2016 at 15:53:39 UTC, Manu wrote:So, you're saying that if you have an 'I' pointer, which may be implemented by a C++ class, it still needs to be able to cast to Object, and therefore fails? I wonder if a C++ class could somehow be promoted to a D class when being derived in D, by having an Object placed somewhere.It helps that Object is a just a handful of virtual methods. On Tuesday, 26 January 2016 at 16:25:35 UTC, Benjamin Thaut wrote:For a D class the first entry in the vtable is the classinfo. Thus the problem if you derive a D class from a extern(C++) base class. I don't see any way to actually fix this, adjusting the this pointer won't help. Once you derive a D class from a extern(C++) base class it is no longer a fully functional D class. For example monitor (e.g. synchronized methods) won't work.Calypso has "hybrid" D classes inheriting from C++, with this layout: - D vptr - D monitor { start of C++ class } - C++ vptr - C++ fields... - might be other vptr and fields if the C++ class has more than one base { end of C++ class } - D fields... and when downcasted to the C++ base class the "this" pointer gets adjusted to point towards the start of the C++ class.
Jan 26 2016
On 27 Jan 2016 7:10 am, "Elie Morisse via Digitalmars-d" < digitalmars-d puremagic.com> wrote:On Tuesday, 26 January 2016 at 15:53:39 UTC, Manu wrote:implemented by a C++ class, it still needs to be able to cast to Object, and therefore fails? I wonder if a C++ class could somehow be promoted to a D class when being derived in D, by having an Object placed somewhere.So, you're saying that if you have an 'I' pointer, which may beIt helps that Object is a just a handful of virtual methods. On Tuesday, 26 January 2016 at 16:25:35 UTC, Benjamin Thaut wrote:problem if you derive a D class from a extern(C++) base class. I don't see any way to actually fix this, adjusting the this pointer won't help. Once you derive a D class from a extern(C++) base class it is no longer a fully functional D class. For example monitor (e.g. synchronized methods) won't work.For a D class the first entry in the vtable is the classinfo. Thus theCalypso has "hybrid" D classes inheriting from C++, with this layout: - D vptr - D monitor { start of C++ class } - C++ vptr - C++ fields... - might be other vptr and fields if the C++ class has more than one base { end of C++ class } - D fields... and when downcasted to the C++ base class the "this" pointer getsadjusted to point towards the start of the C++ class. This is exactly what I had in mind. An alternative would be to place Object at the start of 'D fields', same fixup logic.
Jan 26 2016
To understand this you have to step back and understand what interfaces actually are. They have one member, and that member is a pointer to its vtbl[]. The vtbl[] is populated with pointers to functions. That is it. There is no runtime type info there. Interfaces are how different languages communicate with each other - Java, D, C++, Basic, etc., support this. This is one reason why there is no RTTI there. An interface is supposed to stand on its own. So yes, D and C++ can communicate via interfaces.
Jan 26 2016