Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
November 22, 2020 betterC: new operator | ||||
---|---|---|---|---|
| ||||
I had assumed that new operator is not available in betterC. But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? How should one cleanup objects? import core.stdc.stdio : printf; extern (C++) abstract class A { void sayHello(); } extern (C++) class B : A { override void sayHello() { printf("hello\n"); } } extern (C) void main() { scope b = new B; b.sayHello(); } |
November 22, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dibyendu Majumdar | On Sunday, 22 November 2020 at 11:54:01 UTC, Dibyendu Majumdar wrote: > But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? Check out: https://p0nce.github.io/d-idioms/#Placement-new-with-emplace |
November 23, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis | On 23/11/2020 12:57 AM, Dennis wrote: > Check out: > https://p0nce.github.io/d-idioms/#Placement-new-with-emplace The question was about -betterC. This won't work, it depends on TypeInfo. https://github.com/dlang/phobos/blob/master/std/conv.d#L5197 |
November 22, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to rikki cattermole | On Sunday, 22 November 2020 at 12:11:39 UTC, rikki cattermole wrote:
>
> The question was about -betterC.
>
> This won't work, it depends on TypeInfo.
I think Adam knows how to do it?
|
November 22, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dibyendu Majumdar | On Sunday, 22 November 2020 at 11:54:01 UTC, Dibyendu Majumdar wrote: > I had assumed that new operator is not available in betterC. > > But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? How should one cleanup objects? > > import core.stdc.stdio : printf; > > extern (C++) abstract class A { > void sayHello(); > } > > extern (C++) class B : A { > override void sayHello() { > printf("hello\n"); > } > } > > extern (C) void main() { > scope b = new B; > b.sayHello(); > } You can recreate the vtable using static introspection, POC: --- #!dmd -betterC module a; import core.stdc.stdlib : malloc; import core.stdc.stdio : printf; import std.traits; void setVtable(CT)(ref void** memory) { alias members = __traits(allMembers, CT); void** entries = cast(void**) malloc(members.length + 1); size_t i; static foreach(m; members) static if (isSomeFunction!(__traits(getMember, CT, m))) static foreach (ov; __traits(getVirtualMethods, CT, m)) { entries[i++] = &ov; } memory[0] = *entries; // pointer to vtable memory[1] = null; // monitor memory[2] = null; // interfaces } CT New(CT, A...)(A a) @trusted if (is(CT == class)) { enum size = __traits(classInstanceSize, CT); void** memory = cast(void**) malloc(size); setVtable!CT(memory); CT result = cast(CT) &memory; static if (__traits(hasMember, CT, "__ctor")) result.__ctor(a); return result; } extern (C++) class A { abstract void sayHello() {} } extern (C++) class B : A { override void sayHello() { printf("hello\n"); } } extern (C) void main() { B b = New!B(); b.sayHello(); } --- however note 1. not well tested (e.g overloads) 2. static init of fields is not done because that really rquires TypeInfo, so a ctor has to be used instead. But that's a good start to get things done more properly |
November 22, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | On Sunday, 22 November 2020 at 16:58:03 UTC, Basile B. wrote: > On Sunday, 22 November 2020 at 11:54:01 UTC, Dibyendu Majumdar wrote: >> I had assumed that new operator is not available in betterC. >> >> But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? How should one cleanup objects? > however note > 1. not well tested (e.g overloads) > 2. static init of fields is not done because that really rquires TypeInfo, so a ctor has to be used instead. > > But that's a good start to get things done more properly And the leaks... More simple solution adapted from http://dpldocs.info/this-week-in-d/Blog.Posted_2020_07_27.html#zero-runtime-classes --- #!dmd -betterC extern(C) int printf(const char*, ...); extern(C++) class A { int omg() { return 12; } } extern(C++) class B : A { override int omg() { return 34; } } template New(T) { pragma(mangle, "_D" ~ T.mangleof[1..$] ~ "6__initZ") __gshared extern immutable ubyte[__traits(classInstanceSize, T)] initializer; T New(ref ubyte[__traits(classInstanceSize, T)] memory) { foreach(idx, ref b; memory) { b = initializer.ptr[idx]; } return cast(T) memory.ptr; } } extern(C) int main() { ubyte[__traits(classInstanceSize, A)] buffer; A a = New!B(buffer); printf("hi %d\n", a.omg()); return 0; } --- |
November 24, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dibyendu Majumdar | On Sunday, 22 November 2020 at 11:54:01 UTC, Dibyendu Majumdar wrote: > I had assumed that new operator is not available in betterC. > > But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? How should one cleanup objects? > > import core.stdc.stdio : printf; > > extern (C++) abstract class A { > void sayHello(); > } > > extern (C++) class B : A { > override void sayHello() { > printf("hello\n"); > } > } > > extern (C) void main() { > scope b = new B; > b.sayHello(); > } Mir's RC classes doesn't use TypeInfo and DRuntime, http://mir-algorithm.libmir.org/mir_rc_ptr.html can be used from C++ https://github.com/libmir/mir-algorithm/blob/master/include/mir/rcptr.h and C# https://github.com/libmir/mir.net |
November 24, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | On Sunday, 22 November 2020 at 16:58:03 UTC, Basile B. wrote: > [..] > > But that's a good start to get things done more properly Awesome work! I knew it must be possible, but I never tried implementing that. Small bug fix: > void** entries = cast(void**) malloc(members.length + 1); Here you're allocating space for (members.length + 1) bytes, while I suppose you actually want to allocate this number of vtbl slots (each being void*.sizeof bytes): > auto entries = cast(const(void*)*) malloc((members.length + 1) * (void*).sizeof); I also added `const` for good measure, as the code that the function pointers point to is stored in read-only memory (AFAIK). |
November 24, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to 9il | On Tuesday, 24 November 2020 at 05:40:21 UTC, 9il wrote: > On Sunday, 22 November 2020 at 11:54:01 UTC, Dibyendu Majumdar wrote: >> I had assumed that new operator is not available in betterC. >> >> But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? How should one cleanup objects? >> >> import core.stdc.stdio : printf; >> >> extern (C++) abstract class A { >> void sayHello(); >> } >> >> extern (C++) class B : A { >> override void sayHello() { >> printf("hello\n"); >> } >> } >> >> extern (C) void main() { >> scope b = new B; >> b.sayHello(); >> } > > Mir's RC classes doesn't use TypeInfo and DRuntime, > > http://mir-algorithm.libmir.org/mir_rc_ptr.html > > can be used from C++ > > https://github.com/libmir/mir-algorithm/blob/master/include/mir/rcptr.h > > and C# > > https://github.com/libmir/mir.net Nice! However, how do you initialize the vtbl of the extern (C++) class? I briefly had a look and mir.rc.ptr.createRC [1] calls mir.conv.emplace [2], which is a public import of core.lifetime.emplace, which as far as I can see uses typeinfo for that [3]. You also have a custom typeinfo implementation in mir.typeinfo [4], but I didn't see anything regarding initializing the vtbl pointer in there, just about the pointer to the destructor. Anyway, impressive work on making the interoperability between D, C++ and .NET more seamless! As a former C# developer, mir.net looks much simpler to use then other marshaling techniques for e.g. C/C++. What is the relation between mir.net and autowrap's support for .NET [5]? [1]: https://github.com/libmir/mir-algorithm/blob/2fa78ddb64d5343ae97a8d5acb0012a37d2ae558/source/mir/rc/ptr.d#L263 [2]: https://github.com/libmir/mir-core/blob/8568bf2fceb361ef7804161b1efc5a96e588c24c/source/mir/conv.d#L9 [3]: https://github.com/dlang/druntime/blob/b948c26b8d86be8f058bf538b75df4d422e2a98f/src/core/lifetime.d#L109 [4]: https://github.com/libmir/mir-algorithm/blob/2fa78ddb64d5343ae97a8d5acb0012a37d2ae558/source/mir/type_info.d#L17 [5]: https://github.com/symmetryinvestments/autowrap#generating-net-interfaces |
November 24, 2020 Re: betterC: new operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Petar Kirov [ZombineDev] | On Tuesday, 24 November 2020 at 11:22:30 UTC, Petar Kirov [ZombineDev] wrote: > On Tuesday, 24 November 2020 at 05:40:21 UTC, 9il wrote: >> On Sunday, 22 November 2020 at 11:54:01 UTC, Dibyendu Majumdar wrote: >>> I had assumed that new operator is not available in betterC. >>> >>> But in following code, it seems the only way to initialize the object correctly ... is there another way I am missing? How should one cleanup objects? >>> >>> import core.stdc.stdio : printf; >>> >>> extern (C++) abstract class A { >>> void sayHello(); >>> } >>> >>> extern (C++) class B : A { >>> override void sayHello() { >>> printf("hello\n"); >>> } >>> } >>> >>> extern (C) void main() { >>> scope b = new B; >>> b.sayHello(); >>> } >> >> Mir's RC classes doesn't use TypeInfo and DRuntime, >> >> http://mir-algorithm.libmir.org/mir_rc_ptr.html >> >> can be used from C++ >> >> https://github.com/libmir/mir-algorithm/blob/master/include/mir/rcptr.h >> >> and C# >> >> https://github.com/libmir/mir.net > > Nice! However, how do you initialize the vtbl of the extern (C++) class? I briefly had a look and mir.rc.ptr.createRC [1] calls mir.conv.emplace [2], which is a public import of core.lifetime.emplace, which as far as I can see uses typeinfo for that [3]. You also have a custom typeinfo implementation in mir.typeinfo [4], but I didn't see anything regarding initializing the vtbl pointer in there, just about the pointer to the destructor. `emplace` ref uses type info in compile time. This may not work with betterC flag, I don't know. But it is a compile-time constant, so TypeInfo isn't required to be generated into executable. C++ generates its own vtables. Order of methods should mutch in D and C++, the implementation of a method may be either on the D side or the C++ side. Sometimes you may need to force the C++ compiler to generate vtable using at least one abstract method. vtable for extern(C++) classes is independent of TypeInfo class. But I am not sure how the D compiler generates them. BTW, to make this work, it should be really an extern(C++) interface or abstract classes. So both C++ and D compilers generate vtables. And D has some mangling bugs... but finally we have ported a really huge private C++/C#/protobuffer codebase to D/C# codebase. > Anyway, impressive work on making the interoperability between D, C++ and .NET more seamless! As a former C# developer, mir.net looks much simpler to use than another marshaling techniques for e.g. C/C++. What is the relation between mir.net and autowrap's support for .NET [5]? They are independent projects. |
Copyright © 1999-2021 by the D Language Foundation