Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread evilrat via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 18:12:27 UTC, Gavin Ray wrote:

On Tuesday, 25 May 2021 at 18:03:00 UTC, evilrat wrote:
That last one with someInt is what I warned about. D ctor 
messed up class layout, in this simple case where class data 
isn't used it almost works, but will be practically unusable 
in real scenarios.


Ah =/
You have this in your code example:
```d
static assert(Derived.someInt.offsetof == 16); // that's 
important otherwise D ctor will mess up everything

```

Would this fix it, or is it just not super viable to hack 
around C++ multiple inheritance in D?


Maybe generating some wrapper C++ code to be linked could help 
too?

I'm not sure though/don't really know enough to say


Both this features uses mixins, but does conceptually different 
things, my example with manual vtable casts is simpler but more 
mechanical, and it basically mimics how it actually works.


Anyway the problem is with D side, compiler emits incorrect type 
info/layouts (no wonder, it is clearly stated multiple 
inheritance not supported), and then everything explodes.


So one of the possible workarounds is to separate class layout 
and API with mixins/templates. No idea how it will affect 
usability though, it's quite possible that extending such 
horrible construct from D side would be cumbersome, too much PITA 
to do real job using that thing.

Hard to say for sure without experiments.

Also like I said, D already does half of the work, it just needs 
to collect all base classes and arrange vtable. One of the 
potential blockers could be frontend architecture, I don't know 
how much stuff such change would break, I think pretty much 
everything was designed with single base class in mind.
Like this one, it has 'this' pointer, ctor/dtor and fields, but 
no mention about layouts anywhere.

https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d#L86
The closest what it could be is
https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d#L279



Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Adam D. Ruppe via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 17:52:14 UTC, Gavin Ray wrote:

  void takesADerived(Derived derived);

  extern class Derived : Base1, Base2


Like I said in chat, these are NOT the same thing. The C++ 
Derived is a *sibling* class, not a parent, child, nor binding to 
the D Derived.


All your attempts to pass one off as the other is problematic. If 
you want to bind to the C++ derived, don't provide any bodies for 
the functions - just bind. If you want to inherit from it, you 
must first declare the binding in D, then inherit.




Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Ola Fosheim Grostad via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 18:12:27 UTC, Gavin Ray wrote:
Would this fix it, or is it just not super viable to hack 
around C++ multiple inheritance in D?


You can do anything you want with structs, raw memory, and 
casting, so it is viable, if you have a strong interest for this.


But if you are not a low level programmer you might find it 
tedious.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Gavin Ray via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 18:03:00 UTC, evilrat wrote:
That last one with someInt is what I warned about. D ctor 
messed up class layout, in this simple case where class data 
isn't used it almost works, but will be practically unusable in 
real scenarios.


Ah =/
You have this in your code example:
```d
static assert(Derived.someInt.offsetof == 16); // that's 
important otherwise D ctor will mess up everything

```

Would this fix it, or is it just not super viable to hack around 
C++ multiple inheritance in D?


Maybe generating some wrapper C++ code to be linked could help 
too?

I'm not sure though/don't really know enough to say



Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Gavin Ray via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 11:38:03 UTC, evilrat wrote:
I did some basic testing with code above, it seems class layout 
is recursively linear at least on Windows, and D follows C++ 
rules close enough, at least it works if one comments out all 
but the first base, and the rest can be hand crafted using 
structs and templates.



With this code it is possible to pass back C++ class received 
from C++ code and call it.
So it seems support for multiple inheritance shouldn't be that 
hard to implement (for Windows), no idea how it works on Linux 
though.


Maybe I'll be able to create templated base class that does all 
this stuff with mixins and templates.


like this
```d
extern(C++)
abstract class MultipleInheritance(T...)
{
  // implementation //
}

class Derived : MultipleInheritance!(Base1, Base2)
{ ... }
```


Oh this is brilliant! Absolutely incredible work + findings!

Is this conceptually similar at all to this bit of code that adr 
had given to me?

```d
// Same thing repeated for Abstract2
interface Abstract1 {
/* virtual */ void overrideMe1();
void sayHello();
mixin template Abstract1Impl() {
void sayHello() { import std.stdio; writeln("Hello"); }
}
}

class MyClass : Abstract1, Abstract2 {
  mixin Abstract1Impl; mixin Abstract2Impl;
  override void overrideMe1() { writeln("overrode 1"); }
  override void overrideMe2() { writeln("overrode 2"); }
}

void main() {
auto it = new MyClass();
it.sayHello(); it.sayGoodbye();
it.overrideMe1(); it.overrideMe2();
}
```

---

Also, I wonder if there's a good way to build a quick CLI 
visualization + debugging tool for this using D's `.vtble[]` 
method. I would find it really useful for learning =D


There are also some automatic ABI compliance checker 
tools/libraries, which could be good for programmatically 
verifying that the class produced by D is valid with the ABI of a 
method/class from a C++ library file.


(I know for example, that Qt does this with their Python codegen 
tool, `Shiboken`, for auto-testing the generated code)


- 
https://sourceware.org/libabigail/manual/libabigail-overview.html
- https://github.com/lvc/abi-compliance-checker (this is what 
Shiboken is/was using)


... libabigail provides facilities to perform deep comparisons 
of two ABIs. That is, it can compare the types of two sets of 
functions or variables and represents the result in a way that 
allows it to emit textual reports about the differences.


This allows us to write tools like `abidiff` that can compare 
the ABI of two shared libraries and represent the result in a 
meaningful enough way to help us spot ABI incompatibilities. 
There are several other tools that are built using the Abigail 
framwork.


```sh
$ g++ -g -Wall -shared -o libtest-v0.so test-v0.cc
$ g++ -g -Wall -shared -o libtest-v1.so test-v1.cc
$
$ ../build/tools/abidiff libtest-v0.so libtest-v1.so
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

1 function with some indirect sub-type change:

  [C]'function void foo(S0&)' has some indirect sub-type changes:
parameter 0 of type 'S0&' has sub-type changes:
  in referenced type 'struct S0':
size changed from 32 to 64 bits
1 data member insertion:
  'char S0::inserted_member', at offset 0 (in bits)
1 data member change:
 'int S0::m0' offset changed from 0 to 32
```




Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread evilrat via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 17:52:14 UTC, Gavin Ray wrote:


```d
void main()
{
  Derived dlangDerived = new Derived(123);
  printf("[D] Derived.Base1::getSomething() = %d \n", 
dlangDerived.getSomething());
  printf("[D] Derived.Base2::getOtherThing() = %d \n", 
dlangDerived.getOtherThing());
  printf("[D] Derived.Base1::inheritedFunctionWithArgs(5, 10) = 
%d \n",

  dlangDerived.inheritedFunctionWithArgs(5, 10));
  printf("[D] Calling C++ takesADerived() with D Derived* \n");
  takesADerived(dlangDerived);
}
```
![output](https://i.imgur.com/Plbtlow.png)



That last one with someInt is what I warned about. D ctor messed 
up class layout, in this simple case where class data isn't used 
it almost works, but will be practically unusable in real 
scenarios.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread Gavin Ray via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 06:02:55 UTC, evilrat wrote:
Anyway all this stuff requires thorough research & testing as 
such ABI tinkering is very easy to mess up and very hard to 
debug, for example if you mess up the order(functions layout) 
it can land on another final method call that seemingly work 
but in debugger you'll see that you can't hit breakpoint in 
that method.

Happy debugging time!


Ahh, that works!

It also works without the `cast(BaseType)` if you use `alias` in 
the class:

```d
import core.stdc.stdio : printf;
extern (C++)
{
  void takesADerived(Derived derived);
  Derived createTestDerivedCPP();

  extern interface Base1
  {
void overrideMe1();

pragma(mangle, "?getSomething@Base1@@QEAA?BHXZ")
final int getSomething();

pragma(mangle, "?inheritedFunctionWithArgs@Base1@@QEAAHHH@Z")
final int inheritedFunctionWithArgs(int x, int y);
  }

  extern interface Base2
  {
void overrideMe2();

pragma(mangle "?getOtherThing@Base2@@QEAA?BHXZ")
final int getOtherThing();
  }

  extern class Derived : Base1, Base2
  {
int someInt;

alias getSomething = Base1.getSomething;
alias inheritedFunctionWithArgs = 
Base1.inheritedFunctionWithArgs;


this(int someIntVal) { this.someInt = someIntVal; }

void overrideMe1() { printf("[D] Dlang Derived overrideMe1 
called \n"); }
void overrideMe2() { printf("[D] Dlang Derived overrideMe1 
called \n"); }

  }
}

void main()
{
  Derived dlangDerived = new Derived(123);
  printf("[D] Derived.Base1::getSomething() = %d \n", 
dlangDerived.getSomething());
  printf("[D] Derived.Base2::getOtherThing() = %d \n", 
dlangDerived.getOtherThing());
  printf("[D] Derived.Base1::inheritedFunctionWithArgs(5, 10) = 
%d \n",

  dlangDerived.inheritedFunctionWithArgs(5, 10));
  printf("[D] Calling C++ takesADerived() with D Derived* \n");
  takesADerived(dlangDerived);
}
```

![output](https://i.imgur.com/Plbtlow.png)

Just you wait, I'll learn enough to be of any use contributing to 
OMG yet! haha


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread evilrat via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 08:10:25 UTC, sighoya wrote:

On Tuesday, 25 May 2021 at 02:47:19 UTC, Gavin Ray wrote:


The below seems to work at least, which is encouraging:


Awesome!
At least, it becomes problematic with fields in base classes, 
it would be nice if we could map them to @property annotated 
functions in D interfaces.


I did some basic testing with code above, it seems class layout 
is recursively linear at least on Windows, and D follows C++ 
rules close enough, at least it works if one comments out all but 
the first base, and the rest can be hand crafted using structs 
and templates.



With this code it is possible to pass back C++ class received 
from C++ code and call it.
So it seems support for multiple inheritance shouldn't be that 
hard to implement (for Windows), no idea how it works on Linux 
though.

```d

// replacement for second base
template iBase2() {
// final is needed or it will call overrideMe1 instead of this
final void overrideMe2() {
static struct _layout {
void* b1;
void* b2;
int someInt;
}

_layout* base = cast(_layout*) cast(void*) this;
alias fn = extern(C++) void function(void*);

fn _fn = *cast(fn*) base.b2; // vtable for Base2, 
vtable[0] is overrideMe2

_fn(cast(void*)this);
}
}

class Derived : Base1 //, Base2 {
mixin iBase2 __base2;
alias overrideMe2 = __base2.overrideMe2;


static assert(Derived.someInt.offsetof == 16); // that's 
important otherwise D ctor will mess up everything

}
```

Maybe I'll be able to create templated base class that does all 
this stuff with mixins and templates.


like this
```d
extern(C++)
abstract class MultipleInheritance(T...)
{
  // implementation //
}

class Derived : MultipleInheritance!(Base1, Base2)
{ ... }
```


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread sighoya via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 02:47:19 UTC, Gavin Ray wrote:


The below seems to work at least, which is encouraging:


Awesome!
At least, it becomes problematic with fields in base classes, it 
would be nice if we could map them to @property annotated 
functions in D interfaces.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-25 Thread evilrat via Digitalmars-d-learn

On Tuesday, 25 May 2021 at 02:47:19 UTC, Gavin Ray wrote:


Unfortunately, it does not work if I try to add `final int 
getSomething()` or the other one to the D interfaces, it throws 
a symbol error because the mangled names are slightly different:


```sh

unresolved external symbol "public: int __cdecl 
Base1::getSomething(void)"

  (?getSomething@Base1@@QEAAHXZ)
 T ?getSomething@Base1@@QEAA?BHXZ # < "nm" 
output

```

If I use `nm` and list the symbols, and then try to manually 
use the mangling scheme, it almost works but because the return 
types differ it won't compile =/

```d
extern class Derived : Base1, Base2
{
  int someInt;

  pragma(mangle, "?getOtherThing@Base2@@QEAA?BHXZ")
  int getOtherThing();
}
```

```sh
main.d(29): Error: Function type does not match previously 
declared function with the same mangled name: 
`?getOtherThing@Base2@@QEAA?BHXZ`

main.d(29):Previous IR type: i32 (%main.Base2*)
main.d(29):New IR type:  i32 (%main.Derived*)
```


That's just LDC thing, should work with DMD.
Are you sure `getOtherThing` marked final? Because in your C++ 
class it is not virtual and in your example it is not final as 
well.
In C++ having multiple bases with final method means that both 
Base1 and Base2 have their own instances of that method.


Anyway in order to call it you'll have to cast manually to target 
base.
i.e. if you want to call `Base1::getOtherThing` and you have 
`Derived` you'll have to cast to `Base1`.



```d
Derived d;
// d.getOtherThing(); // likely won't link
(cast(Base1)d) .getOtherThing(); // will call Base1 variant
(cast(Base2)d) .getOtherThing(); // will call Base2 variant
```

It is also possible that you'll have to put them in using mixin 
template so it will create scope for them that doesn't collide 
with each other, though I think it's more of a hack than a 
feature.


Something like
```d
class Derived
{
   mixin base1; // has final getOtherThing
   mixin base2; // has final getOtherThing
}
```

then you can call it almost like in C++
```d
d.base1.getOtherThing();
d.base2.getOtherThing();
```

Anyway all this stuff requires thorough research & testing as 
such ABI tinkering is very easy to mess up and very hard to 
debug, for example if you mess up the order(functions layout) it 
can land on another final method call that seemingly work but in 
debugger you'll see that you can't hit breakpoint in that method.

Happy debugging time!



Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Gavin Ray via Digitalmars-d-learn

On Monday, 24 May 2021 at 20:31:18 UTC, sighoya wrote:

On Monday, 24 May 2021 at 17:39:38 UTC, Gavin Ray wrote:
Hence why I was asking how to make D structs/classes that have 
compatible or identical vtables to multiply inherited objects 
to pass as arguments to `extern (C++)` functions.


I think classes annotated with extern is your only high level 
guaranteed == type safe option to be compatible to other c++ 
classes.


But you seek for the general multiple inheritance case which 
seems not to be supported with `extern`, sadly.
So you stick with manual solutions like template 
metaprogramming or/and raw pointer fiddling.
Anyway, both solutions would require an unsafe cast in the end, 
so you are on your own.


The below seems to work at least, which is encouraging:

```cpp
#include 
#define DLL_EXPORT __declspec(dllexport)

class Base1 {
public:
virtual void overrideMe1() = 0;
const int getSomething() { return 42; }
};

class Base2 {
public:
virtual void overrideMe2() = 0;
const int getOtherThing() { return 99; }
};

class Derived : public Base1, public Base2 {
public:
int someInt;
Derived(int someIntVal) { this->someInt = someIntVal; }
virtual void overrideMe1() override;
virtual void overrideMe2() override;
};

DLL_EXPORT void takesADerived(Derived* derived)
{
printf("[C++] Calling Derived::overrideMe1() \n");
derived->overrideMe1();
printf("[C++] Calling Derived::overrideMe2() \n");
derived->overrideMe2();
printf("[C++] Calling Derived::getSomething() = %d \n",
derived->getSomething());
printf("[C++] Calling Derived::getOtherThing() = %d \n",
derived->getOtherThing());
printf("[C++] Derived::someInt = %d \n", derived->someInt);
}
```

```d
import core.stdc.stdio : printf;

extern (C++)
{
  void takesADerived(Derived derived);

  interface Base1 { void overrideMe1(); }
  interface Base2 { void overrideMe2(); }
  class Derived : Base1, Base2
  {
int someInt;
this(int someIntVal) { this.someInt = someIntVal; }
void overrideMe1() { printf("[D] Dlang Derived overrideMe1 
called \n"); }
void overrideMe2() { printf("[D] Dlang Derived overrideMe1 
called \n"); }

  }
}

void main()
{
  auto dlangDerived = new Derived(123);
  printf("[D] Calling C++ takesADerived() with D Derived* \n");
  takesADerived(dlangDerived);
}
```

![example](https://media.discordapp.net/attachments/242122752436338688/846565538163195974/unknown.png)

Unfortunately, it does not work if I try to add `final int 
getSomething()` or the other one to the D interfaces, it throws a 
symbol error because the mangled names are slightly different:


```sh

unresolved external symbol "public: int __cdecl 
Base1::getSomething(void)"

  (?getSomething@Base1@@QEAAHXZ)
 T ?getSomething@Base1@@QEAA?BHXZ # < "nm" output
```

If I use `nm` and list the symbols, and then try to manually use 
the mangling scheme, it almost works but because the return types 
differ it won't compile =/

```d
extern class Derived : Base1, Base2
{
  int someInt;

  pragma(mangle, "?getOtherThing@Base2@@QEAA?BHXZ")
  int getOtherThing();
}
```

```sh
main.d(29): Error: Function type does not match previously 
declared function with the same mangled name: 
`?getOtherThing@Base2@@QEAA?BHXZ`

main.d(29):Previous IR type: i32 (%main.Base2*)
main.d(29):New IR type:  i32 (%main.Derived*)
```




Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread sighoya via Digitalmars-d-learn

On Monday, 24 May 2021 at 17:39:38 UTC, Gavin Ray wrote:

I'd be grateful for solid information on this


Here is a more informal report how it works in C++:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.23.4735=rep1=pdf

But in the end, I think a byte code analysis is needed to be 
sure. The best tools to visualize have already been proposed by 
you, so I think you are on a good path.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread sighoya via Digitalmars-d-learn

On Monday, 24 May 2021 at 17:39:38 UTC, Gavin Ray wrote:
Hence why I was asking how to make D structs/classes that have 
compatible or identical vtables to multiply inherited objects 
to pass as arguments to `extern (C++)` functions.


I think classes annotated with extern is your only high level 
guaranteed == type safe option to be compatible to other c++ 
classes.


But you seek for the general multiple inheritance case which 
seems not to be supported with `extern`, sadly.
So you stick with manual solutions like template metaprogramming 
or/and raw pointer fiddling.
Anyway, both solutions would require an unsafe cast in the end, 
so you are on your own.






Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Ola Fosheim Grostad via Digitalmars-d-learn

On Monday, 24 May 2021 at 18:52:22 UTC, Ola Fosheim Grostad wrote:
If an informal description is needed then the best option is to 
search the Clang mailing list.


Btw clang docs say they strive to match msvsc, so apparently it 
is platform dependent. The only sensible option is to check with 
Clang people. If using an informal reference such as a book, make 
sure to get an errata, such books tend to have errors...




Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Ola Fosheim Grostad via Digitalmars-d-learn

On Monday, 24 May 2021 at 18:46:00 UTC, Guillaume Piolat wrote:
Multiple inheritance is a rare topic here, I doubt too many 
people know how it works internally.


It is described in the link I gave, or? If I tried to give an 
informal description I would probably be inaccurate and that 
would be worse than reading the spec youself.


If an informal description is needed then the best option is to 
search the Clang mailing list.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Guillaume Piolat via Digitalmars-d-learn

On Monday, 24 May 2021 at 17:39:38 UTC, Gavin Ray wrote:
On Sunday, 23 May 2021 at 21:08:06 UTC, Ola Fosheim Grostad 
wrote:

On Sunday, 23 May 2021 at 21:02:31 UTC, Gavin Ray wrote:
I don't really know anything at all about compilers or 
low-level code -- but is there any high-level notion of 
"inheritance" after it's been compiled?


Yes, in the structure of the vtable, which is why the spec is 
so hard to read.


If possible stick to single inheritance in C++...


Yeah agreed, multiple inheritance is asking for trouble.

But unfortunately when you're binding to existing libraries you 
don't have control over the API


Hence why I was asking how to make D structs/classes that have 
compatible or identical vtables to multiply inherited objects 
to pass as arguments to `extern (C++)` functions.


Also general explanation of what makes a compiled variable 
compatible in terms of vtable with what's expected as an 
argument


I'd be grateful for solid information on this


AFAIK multiple inheritance is described in this book 
https://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545


Multiple inheritance is a rare topic here, I doubt too many 
people know how it works internally.
Java and COM stuck on single-inheritance because it gives you 99% 
bang for the buck, also v-table dispatch in case of multiple 
inheritance is not as straightforward.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Gavin Ray via Digitalmars-d-learn

On Sunday, 23 May 2021 at 21:08:06 UTC, Ola Fosheim Grostad wrote:

On Sunday, 23 May 2021 at 21:02:31 UTC, Gavin Ray wrote:
I don't really know anything at all about compilers or 
low-level code -- but is there any high-level notion of 
"inheritance" after it's been compiled?


Yes, in the structure of the vtable, which is why the spec is 
so hard to read.


If possible stick to single inheritance in C++...


Yeah agreed, multiple inheritance is asking for trouble.

But unfortunately when you're binding to existing libraries you 
don't have control over the API


Hence why I was asking how to make D structs/classes that have 
compatible or identical vtables to multiply inherited objects to 
pass as arguments to `extern (C++)` functions.


Also general explanation of what makes a compiled variable 
compatible in terms of vtable with what's expected as an argument


I'd be grateful for solid information on this


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-24 Thread Alain De Vos via Digitalmars-d-learn

Multiple inheritance is hard.
If you know how it works, just add it to the dmd,ldc compilers.
If no,  try to walk around it :)
With interfaces you can mimic a bit, but don't get Bjarne 
Stroustrup level.


Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-23 Thread Ola Fosheim Grostad via Digitalmars-d-learn

On Sunday, 23 May 2021 at 21:02:31 UTC, Gavin Ray wrote:
I don't really know anything at all about compilers or 
low-level code -- but is there any high-level notion of 
"inheritance" after it's been compiled?


Yes, in the structure of the vtable, which is why the spec is so 
hard to read.


If possible stick to single inheritance in C++...



Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-23 Thread Gavin Ray via Digitalmars-d-learn

On Sunday, 23 May 2021 at 20:16:17 UTC, Ola Fosheim Grostad wrote:

On Sunday, 23 May 2021 at 19:44:01 UTC, Gavin Ray wrote:
So one of the problems with generating D code for bindings to 
C++ is that there's no true/direct multiple inheritance.


If anyone happens to understand well how vtables work and the 
way the compiler treats these things, is there a way to 
hackily make semantically-equivalent objects?


I believe Clang and MSVC are using different layouts.
If I am not wrong clang/gcc are using the Itanium ABI, but I 
could be wrong.


https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable

Maybe ask in the LDC forum as they follow Clang? In my opinion 
MI ought to be supported for binding, but... not sure if anyone 
has considered it.


I guess that's maybe a better way of what I'm asking -- whether 
the vtable is all that matters.


Because I've seen C ABI's for C++ API's that have multiple 
inheritance, and the code was like this (I'll just post a single 
inheritance example but you get the point):


```cpp
class FUnknown {
tresult queryInterface(void*, const TUID, void**);
uint32* addRef(void *);
uint32* release(void *);
};

class IComponentHandler : FUnknown {
tresult beginEdit(void *, ParamID);
tresult performEdit(void *, ParamID, ParamValue);
tresult endEdit(void *, ParamID);
tresult restartComponent(void *, int32);
};

#ifdef __cplusplus
extern "C" {
#endif
typedef struct FUnknownVTable {
tresult (*queryInterface)(void *, const TUID, void **);
uint32 (*addRef)(void *);
uint32 (*release)(void *);
} FUnknownVTable;

typedef struct SFUnknown {
FUnknownVTable *vtable;
} SFUnknown;

typedef struct IComponentHandlerVTable {
FUnknownVTable FUnknown;
tresult (*beginEdit)(void *, ParamID);
tresult (*performEdit)(void *, ParamID, ParamValue);
tresult (*endEdit)(void *, ParamID);
tresult (*restartComponent)(void *, int32);
} IComponentHandlerVTable;

typedef struct SIComponentHandler {
IComponentHandlerVTable *vtable;
} SIComponentHandler;

#ifdef __cplusplus
}
#endif
```

I don't really know anything at all about compilers or low-level 
code -- but is there any high-level notion of "inheritance" after 
it's been compiled?


I felt like it had to turn into something like blocks of memory 
that have pointers to methods and/or to other blocks of memory 
with pointers to methods (vtables). But I also have no clue 樂





Re: How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-23 Thread Ola Fosheim Grostad via Digitalmars-d-learn

On Sunday, 23 May 2021 at 19:44:01 UTC, Gavin Ray wrote:
So one of the problems with generating D code for bindings to 
C++ is that there's no true/direct multiple inheritance.


If anyone happens to understand well how vtables work and the 
way the compiler treats these things, is there a way to hackily 
make semantically-equivalent objects?


I believe Clang and MSVC are using different layouts.
If I am not wrong clang/gcc are using the Itanium ABI, but I 
could be wrong.


https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable

Maybe ask in the LDC forum as they follow Clang? In my opinion MI 
ought to be supported for binding, but... not sure if anyone has 
considered it.


How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

2021-05-23 Thread Gavin Ray via Digitalmars-d-learn
So one of the problems with generating D code for bindings to C++ 
is that there's no true/direct multiple inheritance.


If anyone happens to understand well how vtables work and the way 
the compiler treats these things, is there a way to hackily make 
semantically-equivalent objects?


An example:

```cpp
class Kickable {
  void nonVirtual() { /* impl */ }
  virtual void kick();
}

class Throwable {
  virtual void throw();
}

class KickableThrowable : Kickable, Throwable {}

// KickableThrowable or KickableThrowable*, not really sure which 
is more realistic

void takesKickableThrowable(KickableThrowable* thing) {}
```

Would making a class/struct that has the methods `nonVirtual()`, 
`kick()`, and `throw()` be usable as an argument to 
`takesKickableThrowable()`, since it would contain identical 
members/layout?


```d
extern (C++)
class KickableThrowable {
   void nonVirtual();
   /* override */ void kick() {}
   /* override */ void kick() {}
}

extern (C++)
void takesKickableThrowable(KickableThrowable thing);

takesKickableThrowable(new KickableThrowable());
```

adr had shown me a way to mimic multiple inheritance using 
interfaces and mixin templates, would this be a viable approach?


- See: https://run.dlang.io/is/3rJyMt

```d
interface Abstract1 {
/* virtual */ void overrideMe1();

void sayHello();
mixin template Abstract1Impl() {
void sayHello() { import std.stdio; writeln("Hello"); }
}
}

interface Abstract2 {
/* virtual */ void overrideMe2();

void sayGoodbye();
mixin template Abstract2Impl() {
void sayGoodbye() { import std.stdio; writeln("Goodbye"); 
}

}
}

class MyClass : Abstract1, Abstract2 {
  mixin Abstract1Impl;
  mixin Abstract2Impl;
  override void overrideMe1() { writeln("overrode 1"); }
  override void overrideMe2() { writeln("overrode 2"); }
}
```

---

Also, what is the best way to debug and learn about vtables and 
their impact on interopability in D?


Visual Studio has the "Struct Layout" extension (pictured below), 
and `clang` and `cl.exe` have options to dump vtable/record 
layouts:


```
$ cl.exe test.cpp /d1reportSingleClassLayoutMEOW

class BatMEOW   size(40):
+---
 0  | +--- (base class Mammal)
 0  | ::Breathe

BatMEOW::$vftable@WingedAnimal@:
| -16
 0  | ::Flap



BatMEOW::{dtor} this adjustor: 32
BatMEOW::__delDtor this adjustor: 32
BatMEOW::__vecDelDtor this adjustor: 32
vbi:   class  offset o.vbptr  o.vbte fVtorDisp
  Animal  32   8   4 0
```

```
$ clang -cc1 -fdump-vtable-layouts -emit-llvm  test.cpp

VFTable for 'Animal' (3 entries).
   0 | Animal RTTI
   1 | Animal::~Animal() [scalar deleting]
   2 | void Animal::Eat()


```

```
$ clang -cc1 -fdump-record-layouts -emit-llvm  test.cpp

*** Dumping AST Record Layout
 0 | struct Animal
 0 |   (Animal vftable pointer)
   | [sizeof=8, align=8,
   |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
 0 | struct Mammal
 0 |   (Mammal vftable pointer)
 8 |   (Mammal vbtable pointer)
16 |   struct Animal (virtual base)
16 | (Animal vftable pointer)
   | [sizeof=24, align=8,
   |  nvsize=16, nvalign=8]

```

![vtable inspector cpp](https://i.imgur.com/Xqw6jKG.gif)