www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - C++ constructors, destructors and operator access

reply "Igor Stepanov" <wazar.leollone yahoo.com> writes:
At the current time D have powerful mechanism of access to C++ 
classes.
For access to methods of C++ classes (virtual and not) we can use 
extern(C++) interface.

//С++

class CPPTest1
{
     int a;
     int b;
   public:
     virtual int boom();
     int fun();
     static int gun();
     CPPTest1(int);
     virtual ~CPPTest1();
     int& operator[](size_t);
};

class CPPTest2: public CPPTest1
{
     int boom();
};

//D
extern(C++)interface CPPTest1
{
     int boom();
     static int gun();
     final int fun();
}

extern(C++)interface CPPTest2: CPPTest1
{
     //int boom();
}



As a rule, non-static fields are not public in C++ classes and is 
not part of interface. Thus the most of C++ classes can be bound 
without any glue c++ code.
However D dont support C++ overloaded operators and constructors. 
Yes, we cannot make mapping C++ operators to D operators and C++ 
constructors to D constructors). Nonetheless С++ operators and 
constructors are the simple C++ functions or methods with special 
mangling. Thus I've suggest next mechanism:
Allow special pragma(cppSymbol, string_arg), when string_arg is 
the name of c++ thing.
Example:

extern(C++)interface CPPTest1
{
     int boom();
     static int gun();
     final int fun();
     ///!!!!
     pragma(cppSymbol, "constructor") final void ctor(int); 
//linked with CPPTest1(int);
     pragma(cppSymbol, "destructor") void dtor(); //linked with 
virtual ~CPPTest1();
     pragma(cppSymbol, "[]") ref int indexOf(size_t); //linked 
with int& operator[](size_t);
}

This pragma must apply to the function (or method), use natural 
C++ mangle, but set operatror or constructor or destructor 
mangled name instead of function name.

Is it useful idea?
May 18 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/18/2013 03:23 PM, Igor Stepanov wrote:

 natural C++ mangle
That's part of the problem: C++ name mangling is not standardized. Ali
May 18 2013
parent "Igor Stepanov" <wazar.leollone yahoo.com> writes:
On Saturday, 18 May 2013 at 22:55:34 UTC, Ali Çehreli wrote:
 On 05/18/2013 03:23 PM, Igor Stepanov wrote:

 natural C++ mangle
That's part of the problem: C++ name mangling is not standardized. Ali
But D compilers are using C++ mangle for extern(C++) functions now. I think, this trouble can be solved in a glue layer of compiler. Now, on posix we can use gcc c++ mangle, on windows - dmc/visual c++ mangle. As I know, there is not many kinds of c++ mangle. over 10:) Current implementation use only two: dmc for windows, gcc for posix. If another back-end will be added, we can add another mangle support. I think, C++ to D binding is a very important issue. If D will provide good mechanism of binding, some projects will can be simple moved to D and some project leaders will can choose D to develop his projects.
May 18 2013
prev sibling next sibling parent reply Iain Buclaw <ibuclaw ubuntu.com> writes:
On May 18, 2013 11:25 PM, "Igor Stepanov" <wazar.leollone yahoo.com> wrote:
 At the current time D have powerful mechanism of access to C++ classes.
 For access to methods of C++ classes (virtual and not) we can use
extern(C++) interface.
 //=F3++

 class CPPTest1
 {
     int a;
     int b;
   public:
     virtual int boom();
     int fun();
     static int gun();
     CPPTest1(int);
     virtual ~CPPTest1();
     int& operator[](size_t);
 };

 class CPPTest2: public CPPTest1
 {
     int boom();
 };

 //D
 extern(C++)interface CPPTest1
 {
     int boom();
     static int gun();
     final int fun();
 }

 extern(C++)interface CPPTest2: CPPTest1
 {
     //int boom();
 }



 As a rule, non-static fields are not public in C++ classes and is not
part of interface. Thus the most of C++ classes can be bound without any glue c++ code.
 However D dont support C++ overloaded operators and constructors. Yes, we
cannot make mapping C++ operators to D operators and C++ constructors to D constructors). Nonetheless =F3++ operators and constructors are the simple C++ functions or methods with special mangling. Thus I've suggest next mechanism:
 Allow special pragma(cppSymbol, string_arg), when string_arg is the name
of c++ thing.
 Example:

 extern(C++)interface CPPTest1
 {
     int boom();
     static int gun();
     final int fun();
     ///!!!!
     pragma(cppSymbol, "constructor") final void ctor(int); //linked with
CPPTest1(int);
     pragma(cppSymbol, "destructor") void dtor(); //linked with virtual
~CPPTest1();
     pragma(cppSymbol, "[]") ref int indexOf(size_t); //linked with int&
operator[](size_t);
 }

 This pragma must apply to the function (or method), use natural C++
mangle, but set operatror or constructor or destructor mangled name instead of function name.
 Is it useful idea?
No. Regards --=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0';
May 18 2013
parent reply "Igor Stepanov" <wazar.leollone yahoo.com> writes:
No.
Ok. As I know, there is running process to moving DMD front-end from C++ to D. As I remember, process expect to be gradual. Thus I the same moment will be C++ classes and D classes in the frontend. How you are planning create new C++ objects from D? Are you planning add to all classes special "constructor" static method, which will create new instances of C++ classes and return it, or you see another way to do it?
May 19 2013
parent reply Iain Buclaw <ibuclaw ubuntu.com> writes:
On 19 May 2013 13:20, Igor Stepanov <wazar.leollone yahoo.com> wrote:

 No.

 Ok. As I know, there is running process to moving DMD front-end from C++
 to D. As I remember, process expect to be gradual. Thus I the same moment
 will be C++ classes and D classes in the frontend. How you are planning
 create new C++ objects from D? Are you planning add to all classes special
 "constructor" static method, which will create new instances of C++ classes
 and return it, or you see another way to do it?
All new'ing will be done in D. The C++ glue-layer methods are a problem, and we will be moving to using a visitor interface between the two. -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
May 19 2013
parent reply "Igor Stepanov" <wazar.leollone yahoo.com> writes:
Is this mean, that D functions will _not_ create C++ objects with 
new?
For example:
You have moved parser to D, but you haven't moved expressions to 
D yet.
And you want to create new Expression object in parser (in D 
code), but Expression class defined in C++. What will you do in 
this case?
May 19 2013
parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Igor Stepanov" <wazar.leollone yahoo.com> wrote in message 
news:wuevxraaffhaaceapqfv forum.dlang.org...
 Is this mean, that D functions will _not_ create C++ objects with new?
 For example:
 You have moved parser to D, but you haven't moved expressions to D yet.
 And you want to create new Expression object in parser (in D code), but 
 Expression class defined in C++. What will you do in this case?
This is not how we're moving it. The entire frontend will be moved in one go, there will never be a need to create a C++ class from D. That said, the glue layer will remain in C++ and will need to create instances of classes defined in D. The current glue layer calls 43 different constructors. I don't have a solution for this yet, but it will probably be: a) Extend D to allow creating classes with constructors callable from C++ b) Create/generate factory functions for each class new'd in the glue layer c) Remove all class allocations from the glue layer I'm leaning towards b, or maybe c, and I think you should too.
May 19 2013
parent reply "Igor Stepanov" <wazar.leollone yahoo.com> writes:
On Sunday, 19 May 2013 at 13:56:56 UTC, Daniel Murphy wrote:
 "Igor Stepanov" <wazar.leollone yahoo.com> wrote in message
 news:wuevxraaffhaaceapqfv forum.dlang.org...
 Is this mean, that D functions will _not_ create C++ objects 
 with new?
 For example:
 You have moved parser to D, but you haven't moved expressions 
 to D yet.
 And you want to create new Expression object in parser (in D 
 code), but Expression class defined in C++. What will you do 
 in this case?
This is not how we're moving it. The entire frontend will be moved in one go, there will never be a need to create a C++ class from D. That said, the glue layer will remain in C++ and will need to create instances of classes defined in D. The current glue layer calls 43 different constructors. I don't have a solution for this yet, but it will probably be: a) Extend D to allow creating classes with constructors callable from C++ b) Create/generate factory functions for each class new'd in the glue layer c) Remove all class allocations from the glue layer I'm leaning towards b, or maybe c, and I think you should too.
Yes, language shouldn't be modified for the sake of one goal. But do you think, that calling C++ constructors from D is not typical task? I sure, that we must get a common way to bind C++ classes to D. No templates, no exceptions. But operators and constructors/destructors is needed. It may be special tool, that eat C++ header and return D file + C++ glue file. This util should transform all fields and constructors to D final methods for extern(C++) interface. In addition to this tool we can make a D binding layer, which simplify typical operations such as creating C++ objects using ::operator new() (or class operator new() if in exists) and destroying with operator delete() (local or global). By the way: Why D disallow static __gshared C++ variables in classes? This is a principled feature (if yes: why?) or omission?
May 19 2013
parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Igor Stepanov" <wazar.leollone yahoo.com> wrote in message 
news:pckdwxwvumenyzbuvdpv forum.dlang.org...
 Yes, language shouldn't be modified for the sake of one goal.
 But do you think, that calling C++ constructors from D is not typical 
 task? I sure, that we must get a common way to bind C++ classes to D. No 
 templates, no exceptions. But operators and constructors/destructors is 
 needed. It may be special tool, that eat C++ header and return D file + 
 C++ glue file. This util should transform all fields and constructors to D 
 final methods for extern(C++) interface.
 In addition to this tool we can make a D binding layer, which simplify 
 typical operations such as creating C++ objects using ::operator new() (or 
 class operator new() if in exists) and destroying with  operator delete() 
 (local or global).
Mapping constructors is complicated... Do they have the same semantics in both languages? Both on the heap and on the stack? Eg. how on earth do you map a default constructor for a struct? Same problems with destructors. Which allocator do you use for the heap? etc Operator overloads are much worse, they just don't all map. Do we support part of the set? Or add the missing ones to D? eg comparison operators
 By the way: Why D disallow static __gshared C++ variables in classes? This 
 is a principled feature (if yes: why?) or omission?
It does? Is this problem linux only? I don't see any reason why it would be excluded on purpose. That said, extern(C++) is mostly untested. There are some truly awful bugs lurking if you try to use complicated types/declarations. This is slowly improving.
May 20 2013
parent "Igor Stepanov" <wazar.leollone yahoo.com> writes:
 Mapping constructors is complicated...  Operator overloads are 
 much worse, they just don't all map.
You have misunderstood me. I spoke out against the mapping. I spoke only about access. For example if we automatically generate a binding extern(C++) interface we can add a special methods to access to operators and constructors/destructors. For example: С++: class Foo { int operator<(const Foo&); int operator>(const Foo&); int& operator[](size_t); Foo(); ~Foo(); }; D automatically generated interface: extern(C++) interface Foo { final int __operator_lt(const Foo); final int __operator_gt(const Foo); final ref int __operator_index(size_t); final void __constructor(); final void __destructor(); } Those operator-access methods shouldn't have operator semantic in D. If user want to use C++ __operator_lt for compare objects in D, him cat manually create opCmp method and use __operator_lt in it. But it is user task. I think, we should only provide access to operators and constructors methods. About constructors: In addition those methods we can add some information methods. For example size_t __sizeof() method which return size of this object. After this we can provide some allocate+constructor functions. For example: auto foo = cppNewClass!Foo(args); This template functions perform next actions: 1. Try to find overloaded operator new(). If overloaded new has been finded then cppNewClass will use it, otherwise cppNewClass will use default new. 2. Try to find constructor, which can called with specified args. 3. Allocate memory using __sizeof() method. 4. Call constructor over alloated memory. for pair to cppNewClass can be provided cppDeleteClass function with same semantic. This support layer will very simplify interface with C++ code.
 By the way: Why D disallow static __gshared C++ variables in 
 classes? This is a principled feature (if yes: why?) or 
 omission?
It does? Is this problem linux only? I don't see any reason why it would be excluded on purpose.
Ok. I've created pull request https://github.com/D-Programming-Language/dmd/pull/2053
 That said, extern(C++) is mostly untested.  There are some 
 truly awful bugs
 lurking if you try to use complicated types/declarations.  This 
 is slowly
 improving.
I've bumped two old bugzilla issues about extern(C++) http://d.puremagic.com/issues/show_bug.cgi?id=1687 http://d.puremagic.com/issues/show_bug.cgi?id=4620 Please comment it and close if they are invalid.
May 20 2013
prev sibling next sibling parent "evilrat" <evilrat666 gmail.com> writes:
On Saturday, 18 May 2013 at 22:23:51 UTC, Igor Stepanov wrote:
 At the current time D have powerful mechanism of access to C++ 
 classes.
 For access to methods of C++ classes (virtual and not) we can 
 use extern(C++) interface.

 //С++

 class CPPTest1
 {
     int a;
     int b;
   public:
     virtual int boom();
     int fun();
     static int gun();
     CPPTest1(int);
     virtual ~CPPTest1();
     int& operator[](size_t);
 };

 class CPPTest2: public CPPTest1
 {
     int boom();
 };

 //D
 extern(C++)interface CPPTest1
 {
     int boom();
     static int gun();
     final int fun();
 }

 extern(C++)interface CPPTest2: CPPTest1
 {
     //int boom();
 }



 As a rule, non-static fields are not public in C++ classes and 
 is not part of interface. Thus the most of C++ classes can be 
 bound without any glue c++ code.
 However D dont support C++ overloaded operators and 
 constructors. Yes, we cannot make mapping C++ operators to D 
 operators and C++ constructors to D constructors). Nonetheless 
 С++ operators and constructors are the simple C++ functions or 
 methods with special mangling. Thus I've suggest next mechanism:
 Allow special pragma(cppSymbol, string_arg), when string_arg is 
 the name of c++ thing.
 Example:

 extern(C++)interface CPPTest1
 {
     int boom();
     static int gun();
     final int fun();
     ///!!!!
     pragma(cppSymbol, "constructor") final void ctor(int); 
 //linked with CPPTest1(int);
     pragma(cppSymbol, "destructor") void dtor(); //linked with 
 virtual ~CPPTest1();
     pragma(cppSymbol, "[]") ref int indexOf(size_t); //linked 
 with int& operator[](size_t);
 }

 This pragma must apply to the function (or method), use natural 
 C++ mangle, but set operatror or constructor or destructor 
 mangled name instead of function name.

 Is it useful idea?
you can do this yourself just with mixins and templates, but the real problem is c++ abi and name mangling. so you will need to do runtime search for c++ mangled names and which runtime used, get it and call placement new and ctor(with the help of asm{} of course), do the same for other operators. it is possible, but this is never be safe at least due to non-standardized name mangling. you can write small library which would help doing this all if you really want this.
May 20 2013
prev sibling parent reply "nazriel" <spam dzfl.pl> writes:
On Saturday, 18 May 2013 at 22:23:51 UTC, Igor Stepanov wrote:
 At the current time D have powerful mechanism of access to C++ 
 classes.
 For access to methods of C++ classes (virtual and not) we can 
 use extern(C++) interface.

 //С++

 class CPPTest1
 {
     int a;
     int b;
   public:
     virtual int boom();
     int fun();
     static int gun();
     CPPTest1(int);
     virtual ~CPPTest1();
     int& operator[](size_t);
 };

 class CPPTest2: public CPPTest1
 {
     int boom();
 };

 //D
 extern(C++)interface CPPTest1
 {
     int boom();
     static int gun();
     final int fun();
 }

 extern(C++)interface CPPTest2: CPPTest1
 {
     //int boom();
 }



 As a rule, non-static fields are not public in C++ classes and 
 is not part of interface. Thus the most of C++ classes can be 
 bound without any glue c++ code.
 However D dont support C++ overloaded operators and 
 constructors. Yes, we cannot make mapping C++ operators to D 
 operators and C++ constructors to D constructors). Nonetheless 
 С++ operators and constructors are the simple C++ functions or 
 methods with special mangling. Thus I've suggest next mechanism:
 Allow special pragma(cppSymbol, string_arg), when string_arg is 
 the name of c++ thing.
 Example:

 extern(C++)interface CPPTest1
 {
     int boom();
     static int gun();
     final int fun();
     ///!!!!
     pragma(cppSymbol, "constructor") final void ctor(int); 
 //linked with CPPTest1(int);
     pragma(cppSymbol, "destructor") void dtor(); //linked with 
 virtual ~CPPTest1();
     pragma(cppSymbol, "[]") ref int indexOf(size_t); //linked 
 with int& operator[](size_t);
 }

 This pragma must apply to the function (or method), use natural 
 C++ mangle, but set operatror or constructor or destructor 
 mangled name instead of function name.

 Is it useful idea?
Isn't it possible already with something like: extern(C++) interface Foo { pragma(mangle, typeof(this).mangleof ~ generateCPPMangle!"myOwnFunctionMangling") void foo(); } AFAIK, mangle pragma was merged recently.
May 20 2013
parent reply "nazriel" <spam dzfl.pl> writes:
On Monday, 20 May 2013 at 20:11:27 UTC, nazriel wrote:
 On Saturday, 18 May 2013 at 22:23:51 UTC, Igor Stepanov wrote:
 At the current time D have powerful mechanism of access to C++ 
 classes.
 For access to methods of C++ classes (virtual and not) we can 
 use extern(C++) interface.

 //С++

 class CPPTest1
 {
    int a;
    int b;
  public:
    virtual int boom();
    int fun();
    static int gun();
    CPPTest1(int);
    virtual ~CPPTest1();
    int& operator[](size_t);
 };

 class CPPTest2: public CPPTest1
 {
    int boom();
 };

 //D
 extern(C++)interface CPPTest1
 {
    int boom();
    static int gun();
    final int fun();
 }

 extern(C++)interface CPPTest2: CPPTest1
 {
    //int boom();
 }



 As a rule, non-static fields are not public in C++ classes and 
 is not part of interface. Thus the most of C++ classes can be 
 bound without any glue c++ code.
 However D dont support C++ overloaded operators and 
 constructors. Yes, we cannot make mapping C++ operators to D 
 operators and C++ constructors to D constructors). Nonetheless 
 С++ operators and constructors are the simple C++ functions or 
 methods with special mangling. Thus I've suggest next 
 mechanism:
 Allow special pragma(cppSymbol, string_arg), when string_arg 
 is the name of c++ thing.
 Example:

 extern(C++)interface CPPTest1
 {
    int boom();
    static int gun();
    final int fun();
    ///!!!!
    pragma(cppSymbol, "constructor") final void ctor(int); 
 //linked with CPPTest1(int);
    pragma(cppSymbol, "destructor") void dtor(); //linked with 
 virtual ~CPPTest1();
    pragma(cppSymbol, "[]") ref int indexOf(size_t); //linked 
 with int& operator[](size_t);
 }

 This pragma must apply to the function (or method), use 
 natural C++ mangle, but set operatror or constructor or 
 destructor mangled name instead of function name.

 Is it useful idea?
Isn't it possible already with something like: extern(C++) interface Foo { pragma(mangle, typeof(this).mangleof ~ generateCPPMangle!"myOwnFunctionMangling") void foo(); }
Of course I mean: extern(C++) interface Foo { pragma(mangle, generateCPPMangle!(typeof(this).mangleof, "myOwnFunctionMangling")) void foo(); }
 AFAIK, mangle pragma was merged recently.
May 20 2013
parent "Igor Stepanov" <wazar.leollone yahoo.com> writes:
On Monday, 20 May 2013 at 20:13:47 UTC, nazriel wrote:
 On Monday, 20 May 2013 at 20:11:27 UTC, nazriel wrote:
 On Saturday, 18 May 2013 at 22:23:51 UTC, Igor Stepanov wrote:
 At the current time D have powerful mechanism of access to 
 C++ classes.
 For access to methods of C++ classes (virtual and not) we can 
 use extern(C++) interface.

 //С++

 class CPPTest1
 {
   int a;
   int b;
 public:
   virtual int boom();
   int fun();
   static int gun();
   CPPTest1(int);
   virtual ~CPPTest1();
   int& operator[](size_t);
 };

 class CPPTest2: public CPPTest1
 {
   int boom();
 };

 //D
 extern(C++)interface CPPTest1
 {
   int boom();
   static int gun();
   final int fun();
 }

 extern(C++)interface CPPTest2: CPPTest1
 {
   //int boom();
 }



 As a rule, non-static fields are not public in C++ classes 
 and is not part of interface. Thus the most of C++ classes 
 can be bound without any glue c++ code.
 However D dont support C++ overloaded operators and 
 constructors. Yes, we cannot make mapping C++ operators to D 
 operators and C++ constructors to D constructors). 
 Nonetheless С++ operators and constructors are the simple C++ 
 functions or methods with special mangling. Thus I've suggest 
 next mechanism:
 Allow special pragma(cppSymbol, string_arg), when string_arg 
 is the name of c++ thing.
 Example:

 extern(C++)interface CPPTest1
 {
   int boom();
   static int gun();
   final int fun();
   ///!!!!
   pragma(cppSymbol, "constructor") final void ctor(int); 
 //linked with CPPTest1(int);
   pragma(cppSymbol, "destructor") void dtor(); //linked with 
 virtual ~CPPTest1();
   pragma(cppSymbol, "[]") ref int indexOf(size_t); //linked 
 with int& operator[](size_t);
 }

 This pragma must apply to the function (or method), use 
 natural C++ mangle, but set operatror or constructor or 
 destructor mangled name instead of function name.

 Is it useful idea?
Isn't it possible already with something like: extern(C++) interface Foo { pragma(mangle, typeof(this).mangleof ~ generateCPPMangle!"myOwnFunctionMangling") void foo(); }
Of course I mean: extern(C++) interface Foo { pragma(mangle, generateCPPMangle!(typeof(this).mangleof, "myOwnFunctionMangling")) void foo(); }
 AFAIK, mangle pragma was merged recently.
If we'll implement generateCPPMangle template, we'll can do all:) This way one of the possible. There are another way to do it. I don't know, what a best way now. But I think, this (simple binding C++ code to D) is important issue and we should solve it using one of the possible way.
May 20 2013