www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - extern (C++) including bodies of member functions?

reply cy <dlang verge.info.tm> writes:
I would never (ever) do this myself, but trying to understand 
dmd, the code is absolutely packed with things like this:

extern(C++) class Package : ScopeDSymbol
{
...
   override const(char)* kind() const
   {
      return "package";
   }
...
   override final inout(Package) isPackage() inout
   {
      return this;
   }
...etc...
}

How exactly does that... work? Is the body of such a member 
function written in the D Programming Language? Or is it some 
weird hybrid of D and C++ that just has a human programmer brain 
taking into account all the times that differing name mangling 
might produce different code? I mean, Package.resolve for 
instance is a non-trivial function. Can you not use templates 
inside such a function? Can you only use other "extern(C++)" 
types? Can you import from other modules, inside such a function?

The documents say nothing about this, only defining their 
examples as stubs, like
extern(C++) class Foo {
   void bar();
}

The documentation also avoids any memory allocation in D, instead 
assuming C++ routines like createInstance to use malloc to 
allocate the classes. But the code in dmd makes extensive use of 
things like this:
extern(C++) ... {
   final extern(D) this(...) { ... }
}

How would you create new objects of types that are declared 
extern(C++)? Just new, and mark the constructor as extern(D)?

I realize DMD is a horrible program that was Frankensteined from 
C++ code ages ago and is practically still C++ itself, and that 
DMD has to have /full/ control of symbol mangling, but it is also 
sort of important, not just as a D compiler, but as one of the 
only programs left in the world that produces optimized assembly, 
rather than passing it on to gcc or LLVM. So, understanding it is 
kind of an interest of mine.
Jul 15 2016
parent reply Jacob Carlborg <doob me.com> writes:
On 2016-07-15 19:52, cy wrote:
 I would never (ever) do this myself, but trying to understand dmd, the
 code is absolutely packed with things like this:

 extern(C++) class Package : ScopeDSymbol
 {
 ...
   override const(char)* kind() const
   {
      return "package";
   }
 ...
   override final inout(Package) isPackage() inout
   {
      return this;
   }
 ...etc...
 }

 How exactly does that... work? Is the body of such a member function
 written in the D Programming Language?
Yes. Just as it's possible to call C function from D, it's possible to implement functions in D that can be called from C. This compatibility applies C++ and Objective-C as well. When the D compiler sees a "extern(C++)" declaration it will adopt the code and output the data structures to be compatible with C++. For example, the location of the vtable, name mangling and so on.
 The documents say nothing about this, only defining their examples as
 stubs, like
 extern(C++) class Foo {
   void bar();
 }

 The documentation also avoids any memory allocation in D, instead
 assuming C++ routines like createInstance to use malloc to allocate the
 classes. But the code in dmd makes extensive use of things like this:
 extern(C++) ... {
   final extern(D) this(...) { ... }
 }
IIRC, it's not possible to call a C++ constructor from D. That's why "extern(D) this" is used to be able to do the memory allocation from the D side.
 How would you create new objects of types that are declared extern(C++)?
 Just new, and mark the constructor as extern(D)?

 I realize DMD is a horrible program that was Frankensteined from C++
 code ages ago and is practically still C++ itself
The front end was only fairly recently converted to D. -- /Jacob Carlborg
Jul 15 2016
parent reply cy <dlang verge.info.tm> writes:
On Friday, 15 July 2016 at 19:20:52 UTC, Jacob Carlborg wrote:
 Yes. Just as it's possible to call C function from D, it's 
 possible to implement functions in D that can be called from C. 
 This compatibility applies C++ and Objective-C as well.
So, it applies to member functions too (for C++)? Just as if you passed an extern(C++) directive to each one? And only their signature/mangling is changed, so that say in gdb for instance, they represent Type::member instead of zzTypezdxqdstuffmember?
 The front end was only fairly recently converted to D.
Oh, I thought it happened a while ago, like when D2 came out. (Or was D2 recent as well?)
Jul 15 2016
parent Jacob Carlborg <doob me.com> writes:
On 2016-07-16 04:01, cy wrote:

 So, it applies to member functions too (for C++)? Just as if you passed
 an extern(C++) directive to each one? And only their signature/mangling
 is changed, so that say in gdb for instance, they represent Type::member
 instead of zzTypezdxqdstuffmember?
Yes. It's a bit more than the mangling that changes. The layout of the class/struct needs to be correct and the this pointer needs to be passed correctly.
 Oh, I thought it happened a while ago, like when D2 came out. (Or was D2
 recent as well?)
No, D2 was started in something like 2007. The compiler was converted last year in August. -- /Jacob Carlborg
Jul 16 2016