Jump to page: 1 2
Thread overview
betterC: new operator
4 days ago
Dennis
4 days ago
Basile B.
4 days ago
Basile B.
2 days ago
9il
2 days ago
9il
2 days ago
9il
4 days ago
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();
}

4 days ago
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

4 days ago
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
4 days ago
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?
4 days ago
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
4 days ago
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;
}
---
2 days ago
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



2 days ago
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).
2 days ago
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
2 days ago
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.
« First   ‹ Prev
1 2