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: Passing a derived class where base class is defined as ref parameter

2021-12-13 Thread Mike Parker via Digitalmars-d-learn

On Monday, 13 December 2021 at 22:06:45 UTC, chopchop wrote:

If I remove the ref, it works as expected, that is to say I can 
give a derived class as parameter. I have an idea why it does 
not work, but I think a c++ reference would work, ie incr(A& 
console) would accept a B as parameter. What the logic here?


TL:DR it's because there are two levels of indirection.

What's happening here is that `ref A` in D *is not* equivalent to 
`A&` in C++. That's because D classes are reference types like 
Java classes, not value types like C++ classes. Your `b` is a 
handle to an instance, not an instance itself. It's more akin to 
`B*` in C++. So that means that your `ref A` is like `A**` in 
C++. And I believe you'll find that `B**` in C++ is not 
implicitly convertible to `A**`.


Since `ref` in D is just a pointer under the hood, we can be more 
explicit like so:


```d
void incr(A* a)
{
writeln(a.i);
}

B b = new B();
incr(&b);
```

In this case, compilation also fails. `B*` is not implicitly 
convertible to `A*`. Again, this is equivalent to `B**` and `A**` 
in C++.


In this case, you can explicitly do the conversion with a cast: 
`incr(cast(A*)&b);`


But consider what happens in this case:

```d
void incr(A* a)
{
*a = new A;
}

B b = new B();
incr(cast(A*)&b);
writeln(b.j);
```

Your `b` is no longer a `B`, but still thinks it is.

This is my understanding of why implicit conversion is disallowed 
when multiple levels of indirection are involved.


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: Passing a derived class where base class is defined as ref parameter

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

On Monday, 13 December 2021 at 22:30:59 UTC, Adam D Ruppe wrote:

On Monday, 13 December 2021 at 22:06:45 UTC, chopchop wrote:
If I remove the ref, it works as expected, that is to say I 
can give a derived class as parameter.


Why are you using the ref to begin with?


What the logic here?


Consider this:


class C : A {}

void incr(ref A a) {
   a = new C;
}

B b = new B;
incr(b);
// oops b now got rebound to a C instead of to a B, which 
breaks everything


But `B` is not a child of `A`, why should it be accepted in a 
function that accepts `A` as a parameter? It's not implicitly 
convertible to `A`


Re: Why code failed to compile for foo2?

2021-12-13 Thread Tejas via Digitalmars-d-learn
On Monday, 13 December 2021 at 20:43:51 UTC, Steven Schveighoffer 
wrote:

On 12/11/21 10:02 PM, apz28 wrote:
On Sunday, 12 December 2021 at 00:02:25 UTC, Stanislav Blinov 
wrote:
@apz28, I can't figure out the intent here. To convert result 
of abs to an unsigned?


The function logic works only for unsigned type and the 
parameter value can be altered in body hence Unqual. If not 
Unqual, must declare a local var and make a copy. Just asking 
if this can be done to avoid a cast by caller


To translate a bit here, what apz28 is looking for is, given 
ANY value type that implicitly converts from the qualified 
value to the unqualified value, generate *one* function that 
only accepts the unqualified value.


You can wrap like:

```d
void foo2(T)(T v) if (!is(Unqual!T == T))
{
   foo(Unqual!T(t));
}
```

This will inline as if you called it directly (which should 
just whittle down to a direct call to the correct foo2).


But D isn't currently smart enough to see through aliases, so 
IFTI will not work for what you are doing, even in a case like:


```d
template foo2(T) if (!isUnqual!T == T)
{
   alias foo2 = .foo2!(Unqual!T);
}
```

It would be nice if IFTI gave some hooks between the parameter 
and the deduction, but it currently doesn't.


-Steve


Is there anything wrong with the answer I posted?

Can you please tell me if there's anything dissatisfactory about 
it? I feel like it does everything the OP wants.


Also, am I wrong in using `Unconst` over `Unqual`? Isn't `Unqual` 
overkill if you just want to cast away `const`?


Re: Why code failed to compile for foo2?

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

On Saturday, 11 December 2021 at 23:44:59 UTC, Adam Ruppe wrote:
On Saturday, 11 December 2021 at 23:17:17 UTC, Stanislav Blinov 
wrote:
? No. If it was unsatisfied constraint, the error would've 
shown that.


And if you try to instantiate it, you'll see it is an 
unsatisfied constraint anyway. There's two layers of failure 
here.


Using Unqual there is pretty iffy, i wouldn't bother with it at 
all, but if you do anything, instead qualify it const.


But either way, then the constraint still fails since int isn't 
unsigned.


I'd really recommend simplifying this a lot.


1. This is why there is a diverse logic for language rule vs 
template rule.
The overload functions enjoy all benefits of implicit conversion 
rule but none for template


2. This is why template implementation create more function 
bloats more than it needs to be as compilable example below


import std.traits : isUnsigned, Unqual;
void foo2(T, alias UT1 = Unqual!T)(T x)
// You can create alias UT1 but not able to use it in 
function parameter

if(isUnsigned!T)
{
alias UT2 = Unqual!T;
pragma(msg, T.stringof);
pragma(msg, UT1.stringof);
pragma(msg, UT2.stringof);
}

void main()
{
import std.math;

int s = 1;
foo2(cast(uint)abs(s));
foo2(cast(const(uint))abs(s));
}

Output as below
uint
uint
uint
const(uint)
uint
uint


Re: A debug class has started

2021-12-13 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Dec 13, 2021 at 10:43:14PM +, forkit via Digitalmars-d-learn wrote:
> On Monday, 13 December 2021 at 21:13:25 UTC, H. S. Teoh wrote:
> > 
> > What you should be doing is:
> > 
> > return to!string(str[0 .. len]);
> > 
> > Or just:
> > 
> > return str[0 .. len].idup;
[...]
> oh.. so many different ways...(to both produce the same bug, and also
> to produce the correct output).
> 
> ... it's a little mind boggling ;-)
[...]

It's very simple.  In C, an array decays to a pure pointer.  In D, an
array is a pointer + length pair.  Given a D array, if you want a
pointer to its first element, you use .ptr.   Given a D pointer, if you
want an array, you slice it with [0 .. length].

That's all there is to it.


T

-- 
Almost all proofs have bugs, but almost all theorems are true. -- Paul Pedersen


Re: A debug class has started

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

On Monday, 13 December 2021 at 21:13:25 UTC, H. S. Teoh wrote:


What you should be doing is:

return to!string(str[0 .. len]);

Or just:

return str[0 .. len].idup;


T


oh.. so many different ways...(to both produce the same bug, and 
also to produce the correct output).


... it's a little mind boggling ;-)


// --

module test;

import std : writeln, writefln, assumeUnique;
import std.conv : to;

import core.stdc.string : strdup;
import std.string : toStringz;

void main()
{
string str = "abc;def;ab";

//char* w = cast(char*)str; // nope. a pointer to a string 
constant is
// (supposed to be) immutable, so 
expect undefined behaviour.


char* w = strdup(cast(char*)str); // ok
//char* w = cast(char*)str.toStringz; // also ok
//char* w = cast(char*)str.dup; // also ok
//char* w = str.dup.ptr; // also ok

writeln(replaceChar(w, str.length, ';', 'X'));
}

immutable(char)[] replaceChar(char* str, ulong len, char ch1, 
char ch2)

{
for (ulong i = 0; i < len; i++)
{
if (str[i] == ch1)
{
writefln("Found %c at str[%d]", ch1, i); // fine
str[i] = ch2;
}
}

//return to!(immutable(char)[])(str); // nope .. issue with 
null terminator perhaps ??

return str[0 .. len].idup; // ok
//return str[0 .. len].dup; // also ok
//return to!string(str[0 .. len]); // also ok
//return assumeUnique(str[0..len]); // also ok
}


// -



Re: Passing a derived class where base class is defined as ref parameter

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

On Monday, 13 December 2021 at 22:06:45 UTC, chopchop wrote:
If I remove the ref, it works as expected, that is to say I can 
give a derived class as parameter.


Why are you using the ref to begin with?


What the logic here?


Consider this:


class C : A {}

void incr(ref A a) {
   a = new C;
}

B b = new B;
incr(b);
// oops b now got rebound to a C instead of to a B, which breaks 
everything


Passing a derived class where base class is defined as ref parameter

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

Hi guys,

below a small piece of code, which does not compile because "b" 
of type B can not be passed as ref parameter to incr(ref A a).


If I remove the ref, it works as expected, that is to say I can 
give a derived class as parameter. I have an idea why it does not 
work, but I think a c++ reference would work, ie incr(A& console) 
would accept a B as parameter. What the logic here?


Thanks

```
void main()
{
import std.stdio: write, writeln, writef, writefln;

class A
{
int i = 2;
}

class B : A
{
int j= 3;
}

void incr(ref A a)
{
writeln(a.i);
}

B b = new B();
incr(b);

}
```


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: A debug class has started

2021-12-13 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 13 December 2021 at 20:58:42 UTC, forkit wrote:

immutable(char)[] replaceChar(char* str, ulong len, char ch1, 
char ch2)

//snip
return to!(immutable(char)[])(str);
}



You're calling a `to` on a char pointer, which, ostensibly, would 
look for null terminator. Which there may not be any if you do a 
.dup.


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: A debug class has started

2021-12-13 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Dec 13, 2021 at 08:58:42PM +, forkit via Digitalmars-d-learn wrote:
[...]
> immutable(char)[] replaceChar(char* str, ulong len, char ch1, char ch2)
> {
> for (ulong i = 0; i < len; i++)
> {
> if (str[i] == ch1)
> {
> writefln("Found %c at str[%d]", ch1, i); // fine
> str[i] = ch2;
> }
> }
> return to!(immutable(char)[])(str);

This line is your problem:  you have a raw pointer `str` and
force-casting it to an array without specifying its length. Do not
expect anything good to come of this. (In fact I'm surprised it .to even
accepts such a thing!)

What you should be doing is:

return to!string(str[0 .. len]);

Or just:

return str[0 .. len].idup;


T

-- 
Being forced to write comments actually improves code, because it is easier to 
fix a crock than to explain it. -- G. Steele 


Re: A debug class has started

2021-12-13 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Dec 13, 2021 at 08:47:12PM +, forkit via Digitalmars-d-learn wrote:
> On Monday, 13 December 2021 at 20:28:26 UTC, H. S. Teoh wrote:
> > On Mon, Dec 13, 2021 at 08:04:24PM +, forkit via Digitalmars-d-learn
> > wrote:
[...]
> > > (this produces an unpredictable result??)
> > > char* w = cast(char*)str.dup;
> > 
> > Shouldn't you be using:
> > 
> > char* w = str.dup.ptr;
> > 
> > instead??
[...]
> that also produces the same unpredictable result.
> 
> i.e (an extra character from 'somewhere' appears in the output from
> line below)
> writeln(replaceChar(w, str.length, ';', 'X'));
[...]

That's weird. Can you post the minimal code that exhibits this problem?


T

-- 
Prosperity breeds contempt, and poverty breeds consent. -- Suck.com


Re: ImportC std support

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

On Sunday, 12 December 2021 at 08:25:09 UTC, Dave P. wrote:


ImportC is not ready for general use yet.



I think you nailed it ;-)

https://dlang.org/changelog/2.098.1.html





Re: A debug class has started

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

On Monday, 13 December 2021 at 20:28:26 UTC, H. S. Teoh wrote:
On Mon, Dec 13, 2021 at 08:04:24PM +, forkit via 
Digitalmars-d-learn wrote:

On Monday, 13 December 2021 at 12:06:53 UTC, WebFreak001 wrote:
> 
> You should really use `.dup` if you want to mutate your 
> string. (You would need to duplicate anyway if you don't 
> want an unsafe cast)


(this produces an unpredictable result??)
char* w = cast(char*)str.dup;


Shouldn't you be using:

char* w = str.dup.ptr;

instead??


T


so here are all the possible options I've tried. only 2 of these 
actually produce the expected result.


// --
module test;

import std : writeln, writefln;
import std.conv : to;

import core.stdc.string : strdup;
import std.string : toStringz;

void main()
{
string str = "abc;def;ab";

//char* w = cast(char*)str; // NOPE! A string constant is 
immutable, so expect undefined behaviour.


char* w = strdup(cast(char*)str); // ok
//char* w = cast(char*)str.toStringz; // also ok

// all these below result in an extra character from 
'somewhere' appearing in the writeln output

//char* w = cast(char*)str.dup; // nope
//char* w = str.dup.ptr; // nope
//char* w = &dup(cast(const(char)[])str)[0]; // nope

writeln(replaceChar(w, str.length, ';', 'X'));
}

immutable(char)[] replaceChar(char* str, ulong len, char ch1, 
char ch2)

{
for (ulong i = 0; i < len; i++)
{
if (str[i] == ch1)
{
writefln("Found %c at str[%d]", ch1, i); // fine
str[i] = ch2;
}
}
return to!(immutable(char)[])(str);
}
// 


Re: unit test broken [DUB bug?]

2021-12-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 12/12/21 12:54 AM, Chris Katko wrote:

Running 64-bit Linux
```
dmd --version
DMD64 D Compiler v2.098.0-beta.2

dub --version
DUB version 1.27.0-beta.2, built on Sep  7 2021
```

the following code 'compiles' in one project.

```d
unittest
{
gasdindgaslkdgansklnasgdlknaglkgansklsdg;
}

void main(){} // compiles, links, and 'runs unit tests'
```

dub
[shows compiling, linking, then runs]

dub test

```
Running dfile-test-library
All unit tests have been run successfully.
```



`dub test` adds its own main file, and removes yours. So essentially, 
it's not building your app.d file at all.


`dub test` is a utility used to test libraries, which typically do not 
have a main function. It's definitely suspect for dub to do this, and 
it's based on historical baggage.


To test an application with dub, use `dub -b unittest`, which builds the 
application the same as always, just with the `-unittest` switch.


-Steve


Re: A debug class has started

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

On Monday, 13 December 2021 at 20:28:26 UTC, H. S. Teoh wrote:
On Mon, Dec 13, 2021 at 08:04:24PM +, forkit via 
Digitalmars-d-learn wrote:

On Monday, 13 December 2021 at 12:06:53 UTC, WebFreak001 wrote:
> 
> You should really use `.dup` if you want to mutate your 
> string. (You would need to duplicate anyway if you don't 
> want an unsafe cast)


(this produces an unpredictable result??)
char* w = cast(char*)str.dup;


Shouldn't you be using:

char* w = str.dup.ptr;

instead??


T


that also produces the same unpredictable result.

i.e (an extra character from 'somewhere' appears in the output 
from line below)

writeln(replaceChar(w, str.length, ';', 'X'));




Re: Why code failed to compile for foo2?

2021-12-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 12/11/21 10:02 PM, apz28 wrote:

On Sunday, 12 December 2021 at 00:02:25 UTC, Stanislav Blinov wrote:
@apz28, I can't figure out the intent here. To convert result of abs 
to an unsigned?


The function logic works only for unsigned type and the parameter value 
can be altered in body hence Unqual. If not Unqual, must declare a local 
var and make a copy. Just asking if this can be done to avoid a cast by 
caller


To translate a bit here, what apz28 is looking for is, given ANY value 
type that implicitly converts from the qualified value to the 
unqualified value, generate *one* function that only accepts the 
unqualified value.


You can wrap like:

```d
void foo2(T)(T v) if (!is(Unqual!T == T))
{
   foo(Unqual!T(t));
}
```

This will inline as if you called it directly (which should just whittle 
down to a direct call to the correct foo2).


But D isn't currently smart enough to see through aliases, so IFTI will 
not work for what you are doing, even in a case like:


```d
template foo2(T) if (!isUnqual!T == T)
{
   alias foo2 = .foo2!(Unqual!T);
}
```

It would be nice if IFTI gave some hooks between the parameter and the 
deduction, but it currently doesn't.


-Steve


Re: ImportC std support

2021-12-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 12/11/21 4:42 PM, ManKey wrote:

What implementations of the C standard library does importC support?


ImportC isn't really a way to import C. It's a C compiler built into the 
D compiler. It only compiles C11 code *without* any headers (i.e. you 
can't use C standard library).


In order to properly import C headers, you have to first preprocess a C 
file (with a C preprocessor not supplied by D), and then use the output 
from that to build with your D project. And in that case, you likely 
will find it probably doesn't work yet, since it's not a ready feature.


I recommend instead just using D's hand-crafted bindings in `core.stdc` 
package, which do work.


-Steve


Re: A debug class has started

2021-12-13 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Dec 13, 2021 at 08:04:24PM +, forkit via Digitalmars-d-learn wrote:
> On Monday, 13 December 2021 at 12:06:53 UTC, WebFreak001 wrote:
> > 
> > You should really use `.dup` if you want to mutate your string. (You
> > would need to duplicate anyway if you don't want an unsafe cast)
> 
> (this produces an unpredictable result??)
> char* w = cast(char*)str.dup;

Shouldn't you be using:

char* w = str.dup.ptr;

instead??


T

-- 
It is impossible to make anything foolproof because fools are so ingenious. -- 
Sammy


Re: A debug class has started

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

On Monday, 13 December 2021 at 12:06:53 UTC, WebFreak001 wrote:


You should really use `.dup` if you want to mutate your string. 
(You would need to duplicate anyway if you don't want an unsafe 
cast)


(this produces an unpredictable result??)
char* w = cast(char*)str.dup;

(but this seems to work - as expected)
char* w = strdup(cast(char*)str); // import core.stdc.string : 
strdup;


pro-tip for bugs like this: just slap `@safe:` at the start of 
every file, the compiler will tell you everything that is risky


I like this idea. Thanks ;-)



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: unit test broken [DUB bug?]

2021-12-13 Thread Andre Pany via Digitalmars-d-learn

On Sunday, 12 December 2021 at 05:54:44 UTC, Chris Katko wrote:

Running 64-bit Linux
```
dmd --version
DMD64 D Compiler v2.098.0-beta.2

[...]


I really recommend always using dub configurations, especially 
when you want to use unit tests.


The name of the first configuration doesn't matter. It is used by 
default for commands dub, dub build...
The second configuration you name "unittest". This configuration 
is automatically used by command dub test.


In configuration "unittest" you additionally specify 
"mainSourceFile".


Kind regards
Andre


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: A debug class has started

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

On Monday, 13 December 2021 at 11:09:18 UTC, drug wrote:

On 13.12.2021 13:49, forkit wrote:

On Monday, 13 December 2021 at 09:49:05 UTC, forkit wrote:




char* w = cast(char*)str.toStringz; // this seems to be the 
solution


class has ended ;-)


That's because `str` is initialized by a literal and you can 
not change it by definition. When you call `toStringz` it 
duplicates that literal (adding terminating zero at the end) 
and the duplicate is mutable. I would recommend do not use 
`toStringz` and just make duplicate of the literal - 
https://run.dlang.io/is/vaosW0


important: toStringz _may_ do a copy with the current 
implementation but nothing in the docs states it actually does 
so. In fact there is commented out code where it [in the 
past](https://github.com/dlang/phobos/commit/bc412e7c3fa3f124d7f2785223318b45edd4b3e6#diff-b94766ba288f9b4b05ef1a4874e26724750e614afdcddaf4c2071d0f19d91595L217) just dereferenced the memory after the string and checked if it was 0.


You should really use `.dup` if you want to mutate your string. 
(You would need to duplicate anyway if you don't want an unsafe 
cast)


pro-tip for bugs like this: just slap `@safe:` at the start of 
every file, the compiler will tell you everything that is risky 
and the bug will 9/10 times just sort itself out by fixing what 
the compiler complains about. (just recently helped someone with 
this again, was a 3 minute fix for a big code-base where manually 
searching the issue would have taken much longer)


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: A debug class has started

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

On 13.12.2021 14:26, ag0aep6g wrote:

On 13.12.21 12:09, drug wrote:
That's because `str` is initialized by a literal and you can not 
change it by definition. When you call `toStringz` it duplicates that 
literal (adding terminating zero at the end) and the duplicate is 
mutable. I would recommend do not use `toStringz` and just make 
duplicate of the literal - https://run.dlang.io/is/vaosW0


 From the link:


string str = "abc;def;ab".dup; // allocates the string in the heap
char* w = cast(char*)str;
writeln(replaceChar(w, str.length, ';', 'X'));


That still has undefined behavior. You cannot mutate the characters in a 
`string`. It doesn't matter if it came from a literal or `.dup`. Use 
`char[]` instead of `string`.


You're right. I forget to change `string str` to `auto str` or `char[] str`.


Re: A debug class has started

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

On 13.12.21 12:09, drug wrote:
That's because `str` is initialized by a literal and you can not change 
it by definition. When you call `toStringz` it duplicates that literal 
(adding terminating zero at the end) and the duplicate is mutable. I 
would recommend do not use `toStringz` and just make duplicate of the 
literal - https://run.dlang.io/is/vaosW0


From the link:


string str = "abc;def;ab".dup; // allocates the string in the heap
char* w = cast(char*)str;
writeln(replaceChar(w, str.length, ';', 'X'));


That still has undefined behavior. You cannot mutate the characters in a 
`string`. It doesn't matter if it came from a literal or `.dup`. Use 
`char[]` instead of `string`.


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: A debug class has started

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

On 13.12.2021 13:49, forkit wrote:

On Monday, 13 December 2021 at 09:49:05 UTC, forkit wrote:




char* w = cast(char*)str.toStringz; // this seems to be the solution

class has ended ;-)


That's because `str` is initialized by a literal and you can not change 
it by definition. When you call `toStringz` it duplicates that literal 
(adding terminating zero at the end) and the duplicate is mutable. I 
would recommend do not use `toStringz` and just make duplicate of the 
literal - https://run.dlang.io/is/vaosW0


Re: A debug class has started

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

On Monday, 13 December 2021 at 09:49:05 UTC, forkit wrote:




char* w = cast(char*)str.toStringz; // this seems to be the 
solution


class has ended ;-)


Re: A debug class has started

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

On Monday, 13 December 2021 at 09:49:05 UTC, forkit wrote:





oh...

Windows
 - dmd version is 2.098.0-dirty
 - ldc2 version is 1.28 (based on dmd v2.098.0)

Linux
 - dmd version is 2.098
 - ldc2 version is 1.20.1 (based on dmd v2.090.1)




A debug class has started

2021-12-13 Thread forkit via Digitalmars-d-learn
ok. one line in this code is causing a problem (as noted in 
comments)


an explanation as to the cause, is welcome ;-)


// 
module test;

import std : writeln, writefln;
import std.conv : to;

void main()
{
string str = "abc;def;ab";
char* w = cast(char*)str;
writeln(replaceChar(w, str.length, ';', 'X'));
}

immutable(char)[] replaceChar(char* str, ulong len, char ch1, 
char ch2)

{
for (ulong i = 0; i < len; i++)
{
if (str[i] == ch1)
{
writefln("Found %c at str[%d]", ch1, i); // fine

// problem is with this next line:
// the line works fine using DMD on windows - but 
crashes if using LDC on windows

// On Linux, both DMD and LDC -> sigsegv
//str[i] = ch2;
// seems simple enough
// - just replace the char currently in element 
str[i]) with 'X'

}
}
return to!(immutable(char)[])(str);
}
// 


Re: template ctor overload Segmentation fault

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

On Sunday, 12 December 2021 at 19:17:53 UTC, vit wrote:

On Sunday, 12 December 2021 at 18:32:28 UTC, Imperatorn wrote:

On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:

Hello, why does this code fail to compile?

```d
struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}

this(ref scope typeof(this) rhs){
}
}


struct Bar{
Foo!int foo;
}

void main(){
}
```

error: Segmentation fault (core dumped)


What are you trying to accomplish?


Something like this:

```d
import std.traits : CopyConstness;

struct UniquePtr(T){
alias Type = T;

this(Rhs, this This)(scope Rhs rhs)
if(is(CopyConstness!(Rhs, Rhs.Type*) : CopyConstness!(This, 
This.Type*))){

//...
}

//one of copy ctors:
this(ref scope typeof(this) rhs){
//...
}

static UniquePtr make(Args...)(Args args){
return UniquePtr.init;
}
}


void main(){
const UniquePtr!(int) cui = UniquePtr!(const int).make(1);
const UniquePtr!(const int) cuci = UniquePtr!(const 
int).make(1);

UniquePtr!(const int) uci = UniquePtr!(int).make(1);
UniquePtr!(int) ui = UniquePtr!(int).make(1);

const UniquePtr!(int) xcui = UniquePtr!(immutable 
int).make(1);
const UniquePtr!(const int) xcuci = UniquePtr!(immutable 
int).make(1);


}
```

This work but UniquePtr canno't be inside struct because 
Segmentation fault.


This made your previous snippet work:

```d
struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}

this(scope Foo!(T)* rhs){
}
}


struct Bar{
Foo!int foo;
}

void main(){
import std.stdio:writeln;

Bar bar = Bar();
auto BAR = new Bar();
writeln(bar, "\t", BAR, "\t", *BAR);
}
```

Definitely something funky going on behind the scenes.
I also think you should post a bug, like the above user said.


Re: How to loop through characters of a string in D language?

2021-12-13 Thread Ola Fosheim Grøstad via Digitalmars-d-learn
On Friday, 10 December 2021 at 18:47:53 UTC, Stanislav Blinov 
wrote:
Threshold could be relative for short strings and absolute for 
long ones. Makes little sense reallocating if you only waste a 
couple bytes, but makes perfect sense if you've just removed 
pages and pages of semicolons ;)


Like this?

```
@safe:

string prematureoptimizations(string s, char stripchar) @trusted {
import core.memory;
immutable uint flags = 
GC.BlkAttr.NO_SCAN|GC.BlkAttr.APPENDABLE;

char* begin = cast(char*)GC.malloc(s.length+1, flags);
char* end = begin + 1;
foreach(c; s) {
immutable size_t notsemicolon = c != stripchar;
// hack: avoid conditional by writing semicolon outside 
buffer

*(end - notsemicolon) = c;
end += notsemicolon;
}
immutable size_t len = end - begin - 1;
begin = cast(char*)GC.realloc(begin, len, flags);
return cast(string)begin[0..len];
}

void main() {
import std.stdio;
string str = "abc;def;ab";
writeln(prematureoptimizations(str, ';'));
}

```


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: template ctor overload Segmentation fault

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

On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:

Hello, why does this code fail to compile?

```d
struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}

this(ref scope typeof(this) rhs){
}
}


struct Bar{
Foo!int foo;
}

void main(){
}
```

error: Segmentation fault (core dumped)


Firstly, report the crash with the keyword "ice".

Then, there might be something not allowed (in some situations 
the compiler cant decide which ctor to use) but you cant see it 
for now.




Re: Why code failed to compile for foo2?

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

On Sunday, 12 December 2021 at 03:02:28 UTC, apz28 wrote:
On Sunday, 12 December 2021 at 00:02:25 UTC, Stanislav Blinov 
wrote:
@apz28, I can't figure out the intent here. To convert result 
of abs to an unsigned?


The function logic works only for unsigned type and the 
parameter value can be altered in body hence Unqual. If not 
Unqual, must declare a local var and make a copy. Just asking 
if this can be done to avoid a cast by caller


AFAIK stuff like `const int` implicitly converts to `int` since 
`int` is passed by value so the `const`ness of the original value 
is not violated.


That's why code like:
```d
void main(){
const int a = 55;
int b = a;
}
```
compiles and executes.


So, in a similar vein, your code will transform to:

```d
void foo1(ubyte x) {}
void foo1(ushort x) {}
void foo1(uint x) {}
void foo1(ulong x) {}

import std.traits : Unconst;
import std.stdio : writeln;

void foo2(T)(T x) if(is(Unconst!(T) : ulong)) {//You don't need 
Unqual for this

foo3(x);
}


void foo3(ulong param){ //I'm assuming this is your function that 
you will pass your uint to

writeln(param);
}

void main()
{
import std.math;

int s = int.min + 1; //abs returns int.min for abs(int.min) 
lol XD

foo1(abs(s));
foo2(abs(s)); //failed? //Not anymore :D
}
```

Again, please remember that `std.math.algebraic:abs` doesn't 
return `uint` for `int` and so on, please see [the 
documentation](https://dlang.org/phobos/std_math_algebraic.html#.abs):



Returns:
The absolute value of the number. If floating-point or 
integral, the __return type__ will be the __same as the input__.




Limitations
Does not work correctly for signed intergal types and value 
Num.min.