Re: How to pass a class by (const) reference to C++

2021-12-16 Thread Jan via Digitalmars-d-learn

On Thursday, 16 December 2021 at 16:21:30 UTC, Tim wrote:
That looks like another bug in the compiler. pragma(mangle, 
...) should work as a workaround.


Another bug ticket it is then:
https://issues.dlang.org/show_bug.cgi?id=22604


Re: How to pass a class by (const) reference to C++

2021-12-16 Thread Tim via Digitalmars-d-learn

On Thursday, 16 December 2021 at 08:30:14 UTC, Jan wrote:
Ok, next problem. Maybe you know the necessary syntax for this 
one too.



C++
```cpp
class Test
{
public:
  __declspec(dllexport) static const int const_vars[2];
  __declspec(dllexport) static int nonconst_vars[2];
};

const int Test::const_vars[2] = {11, 23};
int Test::nonconst_vars[2] = {12, 24};
```

D
```cpp
extern(C++, class) struct Test
{
extern export static __gshared const(int)[2] const_vars;
extern export static __gshared int[2] nonconst_vars;
}
```

I get the nonconst_vars to link correctly, but for the 
const_vars the mangled name contains one less const than what 
MSVC generates, so I assume I have to wrap this somehow 
differently. I tried "const(int[2])" but that didn't make a 
difference.


D wants to link against:
`?const_vars@Test@@2PAHB`

which is:
`public: static int * const Test::const_vars" ()`

MSVC exports:
`?const_vars@Test@@2QBHB`

which is:
`public: static int const * const Test::const_vars`


Any idea?


That looks like another bug in the compiler. pragma(mangle, ...) 
should work as a workaround.


Re: How to pass a class by (const) reference to C++

2021-12-16 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 22:50:38 UTC, Tim wrote:

On Wednesday, 15 December 2021 at 22:46:01 UTC, Jan wrote:
Btw. should I report this issue somewhere? Is far as I see 
this isn't logged yet:




Yes, it should be reported.


Ok, next problem. Maybe you know the necessary syntax for this 
one too.



C++
```cpp
class Test
{
public:
  __declspec(dllexport) static const int const_vars[2];
  __declspec(dllexport) static int nonconst_vars[2];
};

const int Test::const_vars[2] = {11, 23};
int Test::nonconst_vars[2] = {12, 24};
```

D
```cpp
extern(C++, class) struct Test
{
extern export static __gshared const(int)[2] const_vars;
extern export static __gshared int[2] nonconst_vars;
}
```

I get the nonconst_vars to link correctly, but for the const_vars 
the mangled name contains one less const than what MSVC 
generates, so I assume I have to wrap this somehow differently. I 
tried "const(int[2])" but that didn't make a difference.


D wants to link against:
`?const_vars@Test@@2PAHB`

which is:
`public: static int * const Test::const_vars" ()`

MSVC exports:
`?const_vars@Test@@2QBHB`

which is:
`public: static int const * const Test::const_vars`


Any idea?


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 22:50:38 UTC, Tim wrote:

On Wednesday, 15 December 2021 at 22:46:01 UTC, Jan wrote:
Btw. should I report this issue somewhere? Is far as I see 
this isn't logged yet:




Yes, it should be reported.


https://issues.dlang.org/show_bug.cgi?id=22603


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Tim via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 22:46:01 UTC, Jan wrote:
Btw. should I report this issue somewhere? Is far as I see this 
isn't logged yet:




Yes, it should be reported.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 22:33:15 UTC, Tim wrote:
I agree that __gshared should imply static. That's probably a 
bug in the compiler.


Using `extern` without `export` would only work with static 
linking (on Windows). `export` without `extern` would be 
exporting the variable for others, like `__declspec(dllexport)` 
in C++. `export` and `extern` combined imports the variable, 
like `__declspec(dllimport)`.


That's all very helpful, thanks for the explanations guys.

Btw. should I report this issue somewhere? Is far as I see this 
isn't logged yet:




Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Tim via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 22:01:19 UTC, Jan wrote:

Ha, it works indeed!

```cpp
extern export __gshared static int var;
```

That's a declaration worthy of C++ ! Fewer keywords would be 
too usable :D


Joking aside, I understood the docs such that `__gshared` 
actually *is* `static` in D, no? Also why the `export` when 
it's an extern variable?


I agree that __gshared should imply static. That's probably a bug 
in the compiler.


Using `extern` without `export` would only work with static 
linking (on Windows). `export` without `extern` would be 
exporting the variable for others, like `__declspec(dllexport)` 
in C++. `export` and `extern` combined imports the variable, like 
`__declspec(dllimport)`.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Adam Ruppe via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 22:24:42 UTC, H. S. Teoh wrote:
`__gshared` is needed to coax the compiler into making the 
variable global in the C/C++ sense, i.e., only 1 instance 
across all threads.



it is just normally __gshared implies static automatically. it 
does in like every other context but i guess not in the mangler 
or whatever.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Dec 15, 2021 at 10:01:19PM +, Jan via Digitalmars-d-learn wrote:
> On Wednesday, 15 December 2021 at 21:30:47 UTC, Tim wrote:
[...]
> ```cpp
> extern export __gshared static int var;
> ```
[...]
> Joking aside, I understood the docs such that `__gshared` actually
> *is* `static` in D, no?

No. `static` in this case means the lifetime is the lifetime of the
module. By default, a static variable would be in TLS and would have the
lifetime of the thread that it was instantiated in (and there would be
one instance per thread).

`__gshared` is needed to coax the compiler into making the variable
global in the C/C++ sense, i.e., only 1 instance across all threads.

tl;dr: C static == D __gshared.


T

-- 
Marketing: the art of convincing people to pay for what they didn't need before 
which you fail to deliver after.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 21:30:47 UTC, Tim wrote:

It seems to work if var is additionally static:


Ha, it works indeed!

```cpp
extern export __gshared static int var;
```

That's a declaration worthy of C++ ! Fewer keywords would be too 
usable :D


Joking aside, I understood the docs such that `__gshared` 
actually *is* `static` in D, no? Also why the `export` when it's 
an extern variable?





Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Tim via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 19:28:44 UTC, Jan wrote:

C++
```cpp
class Test
{
public:
  __declspec(dllexport) static int var;
};

int Test::var = 42;
```

D
```cpp
extern(C++, class) struct Test
{
  extern (C++) export extern __gshared int var;
}
```

(also tried without the duplicate extern(C++) and without 
'export')


DLL compiled with Visual Studio 2019. D DLL compiled with a 3 
day old nightly build of DMD.


DMD says:
`error LNK2019: unresolved external symbol "public: static int 
Test::var" (?var@Test@@2HA)`


I've checked the .exp file of the DLL where the symbol is 
defined in, and it has the exact same name there. And yes, I 
correctly link against that DLL in general, other symbols 
located in that DLL are linked just fine by DMD.


I can reproduce your problem. It seems to work if var is 
additionally static:


extern(C++, class) struct Test
{
   extern (C++) export extern static __gshared int var;
}

It's probably a bug, that it does not work without static. The 
documentation says "__gshared may also be applied to member 
variables and local variables. In these cases, __gshared is 
equivalent to static, except that the variable is shared by all 
threads rather than being thread local." 
(https://dlang.org/spec/attribute.html#gshared)




Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 17:10:51 UTC, Tim wrote:

Do you have a test case for your problem?


C++
```cpp
class Test
{
public:
  __declspec(dllexport) static int var;
};

int Test::var = 42;
```

D
```cpp
extern(C++, class) struct Test
{
  extern (C++) export extern __gshared int var;
}
```

(also tried without the duplicate extern(C++) and without 
'export')


DLL compiled with Visual Studio 2019. D DLL compiled with a 3 day 
old nightly build of DMD.


DMD says:
`error LNK2019: unresolved external symbol "public: static int 
Test::var" (?var@Test@@2HA)`


I've checked the .exp file of the DLL where the symbol is defined 
in, and it has the exact same name there. And yes, I correctly 
link against that DLL in general, other symbols located in that 
DLL are linked just fine by DMD.





Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Tim via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 15:20:18 UTC, Jan wrote:
As I was told linking against functions in DLLs works 
perfectly, because it is identical to static linking. Linking 
against global/static variables supposedly differs and that's 
not handled correctly for DLLs. As I said, I talked to someone 
who worked on fixing lots of those issues a while ago and he 
immediately knew about this limitation.


I have used global variables from DLLs successfully. DMD now also 
has a test for C++ DLLs: 
https://github.com/dlang/dmd/blob/master/test/dshell/extra-files/dll_cxx/testdll.d


The variable should be declared like this in C++:
__declspec(dllexport) int value;

It can then be accessed from D with this:
extern (C++) export extern __gshared int value;

Do you have a test case for your problem?


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 12:36:49 UTC, evilrat wrote:
You probably know this but just in case - unlike C++ in D 
variables by default have thread local storage, to link with 
C++ global variable you need to use __gshared storage modifier 
in D, it is similar to 'shared' variable that unlike 'shared' 
tells the compiler "I know how to synchronize it myself".


```d
module a;

struct Foo {}

extern(C++)
__gshared Foo globalFoo;
```


Yeah, did that. As I said the mangled name that DMD chose is 
correct.


As I was told linking against functions in DLLs works perfectly, 
because it is identical to static linking. Linking against 
global/static variables supposedly differs and that's not handled 
correctly for DLLs. As I said, I talked to someone who worked on 
fixing lots of those issues a while ago and he immediately knew 
about this limitation.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Adam D Ruppe via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 10:54:45 UTC, Jan wrote:
Someone with more in-depth knowledge told me, that Windows 
support in D and specifically DLL support is lacking quite a 
bit.


gdc and ldc have the same full support you'd expect coming from 
microsoft c++.


dmd doesn't though. You can make full dlls with dmd just it is 
more diy than automatic.


*Using* dlls of course is something that's been fully supported 
since day one. Either using an import lib or GetProcAddress.






Re: How to pass a class by (const) reference to C++

2021-12-15 Thread evilrat via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 12:02:08 UTC, Jan wrote:
On Wednesday, 15 December 2021 at 11:03:27 UTC, rikki 
cattermole wrote:


On 15/12/2021 11:54 PM, Jan wrote:

On Wednesday, 15 December 2021 at 09:36:54 UTC, Jan wrote:
Unfortunately it's the "annoying little details" that I 
immediately bumped into.


Just another example: I just learned that linking against C++ 
DLLs is quite limited. I ran into the issue that linking in 
an external variable doesn't work (even though the mangled 
name that D chooses is correct), because DLLs work 
differently than static linking does


Are you sure that on the shared library side it was marked as 
exported?


If a symbol is not exported, there is no guarantee (nor reason 
to think) that it will be visible during runtime linking to 
said shared library/executable.


This isn't unique to D, its just how linkers work.


Yep, checked that. Even checked the .exp file and compared the 
mangled name there with the mangled name that D tries to use, 
they are the same.


You probably know this but just in case - unlike C++ in D 
variables by default have thread local storage, to link with C++ 
global variable you need to use __gshared storage modifier in D, 
it is similar to 'shared' variable that unlike 'shared' tells the 
compiler "I know how to synchronize it myself".


```d
module a;

struct Foo {}

extern(C++)
__gshared Foo globalFoo;
```



Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn
On Wednesday, 15 December 2021 at 11:03:27 UTC, rikki cattermole 
wrote:


On 15/12/2021 11:54 PM, Jan wrote:

On Wednesday, 15 December 2021 at 09:36:54 UTC, Jan wrote:
Unfortunately it's the "annoying little details" that I 
immediately bumped into.


Just another example: I just learned that linking against C++ 
DLLs is quite limited. I ran into the issue that linking in an 
external variable doesn't work (even though the mangled name 
that D chooses is correct), because DLLs work differently than 
static linking does.
Someone with more in-depth knowledge told me, that Windows 
support in D and specifically DLL support is lacking quite a 
bit.


Having *only* link compatibility is totally fine, D currently 
just doesn't fulfill that promise, especially not on Windows 
and especially not with DLLs.


Are you sure that on the shared library side it was marked as 
exported?


If a symbol is not exported, there is no guarantee (nor reason 
to think) that it will be visible during runtime linking to 
said shared library/executable.


This isn't unique to D, its just how linkers work.


Yep, checked that. Even checked the .exp file and compared the 
mangled name there with the mangled name that D tries to use, 
they are the same. I know someone who worked on improving DLL 
support for D a while back and he said he had to fix this in D 
but didn't get that merged into DMD back then (since there were 
many other things as well) and now he doesn't have time to work 
on it further :(


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread rikki cattermole via Digitalmars-d-learn



On 15/12/2021 11:54 PM, Jan wrote:

On Wednesday, 15 December 2021 at 09:36:54 UTC, Jan wrote:
Unfortunately it's the "annoying little details" that I immediately 
bumped into.


Just another example: I just learned that linking against C++ DLLs is 
quite limited. I ran into the issue that linking in an external variable 
doesn't work (even though the mangled name that D chooses is correct), 
because DLLs work differently than static linking does.
Someone with more in-depth knowledge told me, that Windows support in D 
and specifically DLL support is lacking quite a bit.


Having *only* link compatibility is totally fine, D currently just 
doesn't fulfill that promise, especially not on Windows and especially 
not with DLLs.


Are you sure that on the shared library side it was marked as exported?

If a symbol is not exported, there is no guarantee (nor reason to think) 
that it will be visible during runtime linking to said shared 
library/executable.


This isn't unique to D, its just how linkers work.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Wednesday, 15 December 2021 at 09:36:54 UTC, Jan wrote:
Unfortunately it's the "annoying little details" that I 
immediately bumped into.


Just another example: I just learned that linking against C++ 
DLLs is quite limited. I ran into the issue that linking in an 
external variable doesn't work (even though the mangled name that 
D chooses is correct), because DLLs work differently than static 
linking does.
Someone with more in-depth knowledge told me, that Windows 
support in D and specifically DLL support is lacking quite a bit.


Having *only* link compatibility is totally fine, D currently 
just doesn't fulfill that promise, especially not on Windows and 
especially not with DLLs.


Re: How to pass a class by (const) reference to C++

2021-12-15 Thread Jan via Digitalmars-d-learn

On Tuesday, 14 December 2021 at 07:50:48 UTC, evilrat wrote:
There is some missing features like above tail ref and const, 
there is minor mangling issues that requires pragma mangle 
sometimes, and other annoying little details.


As far as I can tell from my limited experience, the way D 
approaches interacting with C++ is sound and extremely useful. 
Link compatibility goes a very long way.


Unfortunately it's the "annoying little details" that I 
immediately bumped into. Things that should be no problem at all 
with just link compatibility, like incorrectly mangled functions 
(forgetting about 'const' in return types on Windows) and this 
very, very annoying issue that I can't pass a class by reference 
but only by pointer.


I can understand that passing a class by value might be out of 
scope (though it would be possible, since it works for structs 
just as well), but with pass by reference it's really just D's 
boneheadedness to try to have its own way.


D is a great language, and I want to use it, but as a stand-alone 
language it just doesn't have the ecosystem that I need 
(gamedev). Using it as an integrated scripting language is for me 
the next best thing to benefit from it in a project that is 
otherwise C++. With link compatibility and auto-generating some 
bindings, I can get there eventually, but it's still a lot of 
work with many manually crafted shims. I am currently willing to 
invest a lot of time to try to solve this, but I won't rewrite a 
huge C++ code base just because D can't pass classes by reference.


Other projects will have even more constraints and even less 
willingness to invest time into such an undertaking and just 
scrap the idea early on.


C++ link compatibility was a great idea, but if D wants to expand 
it's user base further, in my opinion it has to polish the 
interop and be willing to make a few sacrifices on it's end, 
because that can save everyone else hundreds of hours of tedious 
work (and maintenance) and thus be the deciding factor for or 
against using D in a C++ project.




Re: How to pass a class by (const) reference to C++

2021-12-13 Thread evilrat via Digitalmars-d-learn

On Tuesday, 14 December 2021 at 06:21:39 UTC, Tejas wrote:


Hey, evilrat, I've seen people make claims that our C++ interop 
has reached phenomenal levels and that going any further would 
basically require a C++ compiler ala ImportC++, the issue is 
just that the docs haven't been updated yet to reflect it.


What do you think about this? Is this really true? Because it 
sure doesn't look that way to me :(


Unfortunately it is mostly true.
There is some missing features like above tail ref and const, 
there is minor mangling issues that requires pragma mangle 
sometimes, and other annoying little details.


Aside from that there is things that requires actual C++ compiler 
OR at least part of it to enable certain C++ features - like the 
example above with pass-by-value for classes certainly requires 
real C++ copy constructor, some operator overloads, use of SFINAE 
instead of CTFE, and I'm sure there is more of such nuances.


All this not going to happen, D spec clearly states it allows 
limited C++ interop by relying on linker mechanics rather than 
being C++ compatible language.


It is now abandoned but there was LDC fork called "Calypso", it 
was a mixed clang/LDC compiler that aimed to achieve seamless 
D/C++ interop and from what I've heard it was working just fine 
without all this hiccups as above.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Tejas via Digitalmars-d-learn

On Monday, 13 December 2021 at 12:08:30 UTC, evilrat wrote:

On Monday, 13 December 2021 at 11:13:12 UTC, Tejas wrote:

On Monday, 13 December 2021 at 09:21:26 UTC, Jan wrote:

[...]


You'll have to use something called a 
[shim](https://en.wikipedia.org/wiki/Shim_(computing)), it 
seems.


For example:

`main.d` :

```d

extern(C++) class A{}

extern(C++) void cppFunc_shim(A arg);

void main(){
A a = new A();
cppFunc_shim(a);
}

```

`cppShim.cpp` :

```c++

class A{};

extern void cppFunc(A const &arg);

void cppFunc_shim(A *param){
const A forwardingVar = A(*param);
cppFunc(forwardingVar);
}

```

`cppFunc.cpp` :

```c++

#include "iostream"
class A{};

void cppFunc(A const &arg){
//std::cout << arg << std::endl;
std::cout << "Called cppFunc :D" << std::endl;
}   

```

Then pass the following on the command line(assuming all files 
are in the same directory):


`ldmd2 main.d cppFunc.o cppShim.o -L-lstdc++`

That's what it took to make it work for me, dunno if more 
convenient methods exist.


Hope it helps :D


Yeah but it sucks to have making C++ wrapper just for this. I 
think either pragma mangle to hammer it in place or helper 
dummy struct with class layout that mimics this shim logic is a 
better solution in such cases.

Literally anything but building C++ code twice for a project.


Hey, evilrat, I've seen people make claims that our C++ interop 
has reached phenomenal levels and that going any further would 
basically require a C++ compiler ala ImportC++, the issue is just 
that the docs haven't been updated yet to reflect it.


What do you think about this? Is this really true? Because it 
sure doesn't look that way to me :(


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Tim via Digitalmars-d-learn

On Monday, 13 December 2021 at 21:17:49 UTC, Jan wrote:
Unfortunately no. Maybe the cast would even make it work, but I 
can't have "A" and "_A" in D as separate types, because the 
class is supposed to link to C++ functions and thus renaming it 
from A to _A breaks that. On the other hand I can't give the 
struct another name either, because that's how it is linked to 
in "CppFunc".


The easiest workaround is probably to set the mangling manually:

pragma(mangle, "_Z7CppFuncRK1A")
extern(C++) void CppFunc(const A arg);

This mangling is for the Itanium ABI, which is used by Linux and 
other operating systems. It needs to be different for Windows.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Jan via Digitalmars-d-learn
On Monday, 13 December 2021 at 12:16:03 UTC, Ola Fosheim Grøstad 
wrote:

On Monday, 13 December 2021 at 12:08:30 UTC, evilrat wrote:
Yeah but it sucks to have making C++ wrapper just for this. I 
think either pragma mangle to hammer it in place or helper 
dummy struct with class layout that mimics this shim logic is 
a better solution in such cases.

Literally anything but building C++ code twice for a project.


Does something like this work?


```
class _A {}
struct A {}

extern(C++) void CppFunc(ref const(A) arg);

void func(_A a){
CppFunc(*cast(A*)a);
}
```


Unfortunately no. Maybe the cast would even make it work, but I 
can't have "A" and "_A" in D as separate types, because the class 
is supposed to link to C++ functions and thus renaming it from A 
to _A breaks that. On the other hand I can't give the struct 
another name either, because that's how it is linked to in 
"CppFunc".




Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Jan via Digitalmars-d-learn

On Monday, 13 December 2021 at 16:29:12 UTC, Tim wrote:
I made a pull request, which changes the mangling to tail const 
for classes passed directly as parameter or return type, but 
now think this would break too much code: 
https://github.com/dlang/dmd/pull/13369
The proposal to add a deref-type-constructor, would also allow 
to have tail const classes.


A 'deref' keyword sounds interesting. I'm not an expert on 
compilers, but thinking about this a bit more, to me it looks 
like the fundamental problem is, that D tries to apply its class 
pointer/reference semantics to C++, even though it could do this 
differently. 'Deref' would only solve one (common) issue. 
However, in C++ it is also very common to treat classes as value 
types. Maybe one could give such a hint to the D compiler instead.


If I have this C++ code:
```cpp
class A { ... };

void AsValue(A value);
void AsPtr(A* value);
void AsConstPtr(const A* value);
void AsRef(A& value);
void AsConstRef(const A& value);
```

Afaik today I can really only bind to functions of the form 
'AsPtr' and 'AsConstPtr'. And if I declare A in D as a struct, I 
could also bind to all the others, but as mentioned above that's 
not always possible.


How about in D I could declare that A should be used like a value 
type to pass it to a function, using the 'struct' keyword:


```cpp
extern(C++) class A { ... }
extern(C++) void AsValue(struct A value);
extern(C++) void AsPtr(A value); // could stay as previously, OR
extern(C++) void AsPtr(struct A* value); // same as above
extern(C++) void AsConstPtr(const(A) value);
extern(C++) void AsConstPtr(const(struct A*) value); // same as 
above

extern(C++) void AsRef(ref struct A value);
extern(C++) void AsConstRef(const(ref struct A) value); // same 
as above

```

So here the 'struct' keyword would tell the compiler to treat A 
like a value type, just as in C++ and thus apply pointer, const 
and reference semantics like in C++. Additionally, if a pure 
'struct A' is encountered, the compiler would need to create a 
copy of the object on the stack, just as it would do for structs, 
to pass it to C++ (which might modify the temporary). I guess 
this would be trickier to implement but then you would be able to 
pass classes to C++ under all circumstances.


The added benefit would be, that this shouldn't change existing 
behavior and thus not break anything.


Unfortunately I have neither the time nor expertise to change DMD 
myself.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Tim via Digitalmars-d-learn

On Monday, 13 December 2021 at 15:21:19 UTC, Jan wrote:
On Monday, 13 December 2021 at 13:02:50 UTC, Ola Fosheim 
Grøstad wrote:
Yes, I wouldn't want to use it, maybe manual mangling is 
better, but still painful. ```const A&``` is so common in C++ 
API's that it really should be supported out-of-the-box.  All 
it takes is adding a deref-type-constructor to the D language 
spec, e.g. ```ref const(@deref(A))```


I fully agree. This pattern is so common in C++, that I am 
surprised D doesn't have a way to do this already. The whole 
idea of linking against C++ is to interop easily, with little 
friction and high performance. Needing to build any shims or 
redesign the C++ side is very much contrary to this goal.


Does anyone know whether such issues have been discussed 
before? I can't imagine I'm the first one to run into this.


A similar issue about tail const classes has already been 
discussed:

https://digitalmars.com/d/archives/digitalmars/D/const_Class_is_mangled_as_Class_const_const_299139.html

I made a pull request, which changes the mangling to tail const 
for classes passed directly as parameter or return type, but now 
think this would break too much code: 
https://github.com/dlang/dmd/pull/13369
The proposal to add a deref-type-constructor, would also allow to 
have tail const classes.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Jan via Digitalmars-d-learn
On Monday, 13 December 2021 at 13:02:50 UTC, Ola Fosheim Grøstad 
wrote:

On Monday, 13 December 2021 at 12:51:17 UTC, evilrat wrote:
That example is still looks very conspicuous because it is 
very likely does nothing on the caller side in C++ as it 
passes a copy.


Yes, I wouldn't want to use it, maybe manual mangling is 
better, but still painful. ```const A&``` is so common in C++ 
API's that it really should be supported out-of-the-box.  All 
it takes is adding a deref-type-constructor to the D language 
spec, e.g. ```ref const(@deref(A))```


I fully agree. This pattern is so common in C++, that I am 
surprised D doesn't have a way to do this already. The whole idea 
of linking against C++ is to interop easily, with little friction 
and high performance. Needing to build any shims or redesign the 
C++ side is very much contrary to this goal.


Does anyone know whether such issues have been discussed before? 
I can't imagine I'm the first one to run into this.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Monday, 13 December 2021 at 12:51:17 UTC, evilrat wrote:
That example is still looks very conspicuous because it is very 
likely does nothing on the caller side in C++ as it passes a 
copy.


Yes, I wouldn't want to use it, maybe manual mangling is better, 
but still painful. ```const A&``` is so common in C++ API's that 
it really should be supported out-of-the-box.  All it takes is 
adding a deref-type-constructor to the D language spec, e.g. 
```ref const(@deref(A))```




Re: How to pass a class by (const) reference to C++

2021-12-13 Thread evilrat via Digitalmars-d-learn
On Monday, 13 December 2021 at 12:16:03 UTC, Ola Fosheim Grøstad 
wrote:

On Monday, 13 December 2021 at 12:08:30 UTC, evilrat wrote:
Yeah but it sucks to have making C++ wrapper just for this. I 
think either pragma mangle to hammer it in place or helper 
dummy struct with class layout that mimics this shim logic is 
a better solution in such cases.

Literally anything but building C++ code twice for a project.


Does something like this work?


```
class _A {}
struct A {}

extern(C++) void CppFunc(ref const(A) arg);

void func(_A a){
CppFunc(*cast(A*)a);
}
```


Only if this struct matches class memory layout, the only 
potential problem is ctor on C++ side.
Also C++ class will likely be NOT zero initialized and have byte 
gaps due to alignment, this can mess up many things including 
(default) equality operators and such.


That example is still looks very conspicuous because it is very 
likely does nothing on the caller side in C++ as it passes a 
copy. Such things may indicate that the library author have no 
idea what he is doing, and it works on occasion.


All this will require extra care or it will explode in your face, 
and is quite hard to debug without such low-level knowledge of 
details.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn

On Monday, 13 December 2021 at 12:08:30 UTC, evilrat wrote:
Yeah but it sucks to have making C++ wrapper just for this. I 
think either pragma mangle to hammer it in place or helper 
dummy struct with class layout that mimics this shim logic is a 
better solution in such cases.

Literally anything but building C++ code twice for a project.


Does something like this work?


```
class _A {}
struct A {}

extern(C++) void CppFunc(ref const(A) arg);

void func(_A a){
CppFunc(*cast(A*)a);
}
```


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
On Monday, 13 December 2021 at 12:16:03 UTC, Ola Fosheim Grøstad 
wrote:

class _A {}
struct A {}


With ```extern(C++)``` on these…



Re: How to pass a class by (const) reference to C++

2021-12-13 Thread evilrat via Digitalmars-d-learn

On Monday, 13 December 2021 at 11:13:12 UTC, Tejas wrote:

On Monday, 13 December 2021 at 09:21:26 UTC, Jan wrote:

On Monday, 13 December 2021 at 07:48:34 UTC, evilrat wrote:

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

In D I have an extern(C++) class:

```cpp
extern(C++) class A
{
~this();

// other stuff
}
```

An a function that takes A by const reference:

```cpp
void CppFunc(const A& arg);
```

But how do I bind this in D ?

```cpp
extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass 
as 'A const * const &'

```

I have solved similar problems with other classes by 
declaring them as struct in D, but that only works for 
classes that have no virtual functions. I now have a class 
where I do need to use a class on the D side, and now I have 
problems passing these objects to C++.


You can tell compiler to mangle it as struct/class using 
extern(C++, struct).


```d
extern (C++, struct) // will use struct mangling even though 
it's a class

class SomeDClass
{
 ...
}
```


I tried this, but it doesn't work, because it seems D decides 
how to pass the object by whether it is a class or struct in 
D, not in C++. So even with the change as you suggested it, it 
still tries to pass the object as a pointer to begin with.


You'll have to use something called a 
[shim](https://en.wikipedia.org/wiki/Shim_(computing)), it 
seems.


For example:

`main.d` :

```d

extern(C++) class A{}

extern(C++) void cppFunc_shim(A arg);

void main(){
A a = new A();
cppFunc_shim(a);
}

```

`cppShim.cpp` :

```c++

class A{};

extern void cppFunc(A const &arg);

void cppFunc_shim(A *param){
const A forwardingVar = A(*param);
cppFunc(forwardingVar);
}

```

`cppFunc.cpp` :

```c++

#include "iostream"
class A{};

void cppFunc(A const &arg){
//std::cout << arg << std::endl;
std::cout << "Called cppFunc :D" << std::endl;
}   

```

Then pass the following on the command line(assuming all files 
are in the same directory):


`ldmd2 main.d cppFunc.o cppShim.o -L-lstdc++`

That's what it took to make it work for me, dunno if more 
convenient methods exist.


Hope it helps :D


Yeah but it sucks to have making C++ wrapper just for this. I 
think either pragma mangle to hammer it in place or helper dummy 
struct with class layout that mimics this shim logic is a better 
solution in such cases.

Literally anything but building C++ code twice for a project.


Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Tejas via Digitalmars-d-learn

On Monday, 13 December 2021 at 09:21:26 UTC, Jan wrote:

On Monday, 13 December 2021 at 07:48:34 UTC, evilrat wrote:

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

In D I have an extern(C++) class:

```cpp
extern(C++) class A
{
~this();

// other stuff
}
```

An a function that takes A by const reference:

```cpp
void CppFunc(const A& arg);
```

But how do I bind this in D ?

```cpp
extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass 
as 'A const * const &'

```

I have solved similar problems with other classes by 
declaring them as struct in D, but that only works for 
classes that have no virtual functions. I now have a class 
where I do need to use a class on the D side, and now I have 
problems passing these objects to C++.


You can tell compiler to mangle it as struct/class using 
extern(C++, struct).


```d
extern (C++, struct) // will use struct mangling even though 
it's a class

class SomeDClass
{
 ...
}
```


I tried this, but it doesn't work, because it seems D decides 
how to pass the object by whether it is a class or struct in D, 
not in C++. So even with the change as you suggested it, it 
still tries to pass the object as a pointer to begin with.


You'll have to use something called a 
[shim](https://en.wikipedia.org/wiki/Shim_(computing)), it seems.


For example:

`main.d` :

```d

extern(C++) class A{}

extern(C++) void cppFunc_shim(A arg);

void main(){
A a = new A();
cppFunc_shim(a);
}

```

`cppShim.cpp` :

```c++

class A{};

extern void cppFunc(A const &arg);

void cppFunc_shim(A *param){
const A forwardingVar = A(*param);
cppFunc(forwardingVar);
}

```

`cppFunc.cpp` :

```c++

#include "iostream"
class A{};

void cppFunc(A const &arg){
//std::cout << arg << std::endl;
std::cout << "Called cppFunc :D" << std::endl;
}   

```

Then pass the following on the command line(assuming all files 
are in the same directory):


`ldmd2 main.d cppFunc.o cppShim.o -L-lstdc++`

That's what it took to make it work for me, dunno if more 
convenient methods exist.


Hope it helps :D



Re: How to pass a class by (const) reference to C++

2021-12-13 Thread Jan via Digitalmars-d-learn

On Monday, 13 December 2021 at 07:48:34 UTC, evilrat wrote:

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

In D I have an extern(C++) class:

```cpp
extern(C++) class A
{
~this();

// other stuff
}
```

An a function that takes A by const reference:

```cpp
void CppFunc(const A& arg);
```

But how do I bind this in D ?

```cpp
extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass 
as 'A const * const &'

```

I have solved similar problems with other classes by declaring 
them as struct in D, but that only works for classes that have 
no virtual functions. I now have a class where I do need to 
use a class on the D side, and now I have problems passing 
these objects to C++.


You can tell compiler to mangle it as struct/class using 
extern(C++, struct).


```d
extern (C++, struct) // will use struct mangling even though 
it's a class

class SomeDClass
{
 ...
}
```


I tried this, but it doesn't work, because it seems D decides how 
to pass the object by whether it is a class or struct in D, not 
in C++. So even with the change as you suggested it, it still 
tries to pass the object as a pointer to begin with.


Re: How to pass a class by (const) reference to C++

2021-12-12 Thread evilrat via Digitalmars-d-learn

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

In D I have an extern(C++) class:

```cpp
extern(C++) class A
{
~this();

// other stuff
}
```

An a function that takes A by const reference:

```cpp
void CppFunc(const A& arg);
```

But how do I bind this in D ?

```cpp
extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass as 
'A const * const &'

```

I have solved similar problems with other classes by declaring 
them as struct in D, but that only works for classes that have 
no virtual functions. I now have a class where I do need to use 
a class on the D side, and now I have problems passing these 
objects to C++.


You can tell compiler to mangle it as struct/class using 
extern(C++, struct).


```d
extern (C++, struct) // will use struct mangling even though it's 
a class

class SomeDClass
{
 ...
}
```