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

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

On Tuesday, 14 December 2021 at 20:58:21 UTC, Adam D Ruppe wrote:
nice. You might want to look at my terminal.d 
(arsd-official:terminal on dub) too which has pretty 
comprehensive functionality for tons of things. Prolly more 
than you need looking at your interface tho but it includes the 
output functions then mouse and real time key inputs, get line 
input, even scrollable areas and more.


Always a pleasure to check your great libs, I will have a look 
and learn probably a lot. But I wont use an external lib because 
it's a demo where all the code must be under contract / covered, 
to meet some strict coding standard. So in worst case I copy the 
code and add unittest / contract / invariant, etc. But original 
authors are always quoted and licences respected ;)




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

2021-12-14 Thread chopchop via Digitalmars-d-learn
On Tuesday, 14 December 2021 at 17:27:13 UTC, Stanislav Blinov 
wrote:
Simple. Don't take a `ref`. Just take a `Console`. Classes in D 
are reference types, you're not making a copy as you would in 
C++ if you were to write `updateFoodToken(Console c)`.


Ah, ok, Reference types! That's great. Definitely my C++ bias 
working against me, good you read my mind :)





Re: Immutability and arrays

2021-12-14 Thread rumbu via Digitalmars-d-learn
On Tuesday, 14 December 2021 at 16:21:03 UTC, Steven 
Schveighoffer wrote:

On 12/14/21 11:19 AM, Steven Schveighoffer wrote:

Er... scratch that, this isn't construction, it should use 
opAssign. Again, probably because memcpy+postblit is used by 
the runtime.


If not reported, it should be.


Simple proof that it is a bug:

```d
immutable (ComplexStruct)[] arr;
ComplexStruct[] arr2;

arr2[0] = arr[0]; // ok
arr2[] = arr[]; // error
```

If you can copy one element, you should be able to copy all the 
elements.


-Steve


Thank you everybody, especially to Steve for the detailed 
explanation.


It seems that every post I put in the learn forum, results in a 
bug report :)


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




Re: Why code failed to compile for foo2?

2021-12-14 Thread Tejas via Digitalmars-d-learn
On Tuesday, 14 December 2021 at 15:14:40 UTC, Steven 
Schveighoffer wrote:

On 12/14/21 12:04 AM, Tejas wrote:

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`?


Unqual is fine for value types, it should work in all cases.

The OP's problem is that it's entirely possible to build an 
overload set with *just* the unqualified types specified (in 
this case, an integral type), but there's not a way to express 
that and still have it work with IFTI.


In other words, if you have a call like:

```d
const int x;
foo2(x);
```

You want to have the parameter be mutable inside foo2. There 
currently isn't a way to express that if `foo2` is an IFTI 
template. The opposite is actually easily expressable:


```d
void foo2(T)(const(T) val)
{
   // only one instantiation of foo2 per const(int), 
immutable(int), int,

   // and now val is const, even if the argument is not
}
```

With a standard function it works just fine due to implicit 
conversion, but with IFTI, there's no way to express it because 
it goes through an alias. The closest you can come is to write 
a wrapper shim that calls the right instantiation. This should 
be OK as long as inlining is happening, but it seems like extra 
work for the optimizer, when it should be easy to express in 
the language somehow.


BTW, there is a related issue: 
https://issues.dlang.org/show_bug.cgi?id=1807


-Steve


Yeah, now I understand he's trying to reduce number of 
instantiations.


In that case, I'd use `inout`, but it'd be the same as your case 
: can't modify the argument anymore.


But we can pass that to another function that accepts `ulong` (as 
that seems to be the OP's usecase anyways), which can then modify 
it :D


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

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

pragma(msg, T.stringof);
foo3(x);
}

void foo3(ulong param){
writeln(param, " before");
param +=10; 
writeln(param, " after"); // can also modify params now
}
void main(){
import std.math;
const int ci = -3;
int i = -2;
immutable int ii = 24342;
foo2(abs(ci));
foo2(abs(i));
foo2(ii);

byte b = 0;
const byte cb;
immutable byte ib;
foo2(b);
foo2(cb);
foo2(ib);

const long cl = 4554;
long l = 12313;
immutable long il = 3242343;
foo2(cl);
foo2(l);
foo2(il);

}
```


Re: Why code failed to compile for foo2?

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

On Tuesday, 14 December 2021 at 13:25:04 UTC, apz28 wrote:

On Tuesday, 14 December 2021 at 05:04:46 UTC, Tejas wrote:

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`?


1. A template function should behave as to replace 4 overload 
functions

There is special logic for parameter type (2 vs 4...)

2. Your implementation does not remove 'const' as below
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

pragma(msg, T.stringof);
writeln(x);
}

void main()
{
import std.math;

const int s1 = -3;
int s2 = -2;
foo2(abs(s1));
foo2(abs(s2));

enum byte b1 = 0;
const byte b2;
byte b3;
foo2(b1);
foo2(b2);
foo2(b3);
}
--Output
const(int)
int
byte
const(byte)
3
2
0
0
0


Then I suggest using `inout`, if you're trying to reduce number 
of template instantiations


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

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

pragma(msg, T.stringof);
writeln(x);
}

void main(){
import std.math;
const int ci = -3;
int i = -2;
immutable int ii = 24342;
foo2(abs(ci));
foo2(abs(i));
foo2(ii);

byte b = 0;
const byte cb;
immutable byte ib;
foo2(b);
foo2(cb);
foo2(ib);

const long cl = 4554;
long l = 12313;
immutable long il = 3242343;
foo2(cl);
foo2(l);
foo2(il);

}

Output(Compile-time):
int
byte
long

Output(Runtime):
3
2
24342

0
0
0

4554
12313
3242343
```




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

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

On Tuesday, 14 December 2021 at 17:20:18 UTC, chopchop wrote:
I am using the "ref" here (I put tinyurl to avoid 
over-referencing the post instead of the github page itself):

https://tinyurl.com/bdddkmub


yeah D classes are automatically ref unlike c++ so you don't need 
the second level of it most often.


Using plain `Object` is what you want most the time, maybe `in 
Object` sometimes. But `ref Object` or `Object*` both very rare 
in D.




Adam, I am actually using your code :)


nice. You might want to look at my terminal.d 
(arsd-official:terminal on dub) too which has pretty 
comprehensive functionality for tons of things. Prolly more than 
you need looking at your interface tho but it includes the output 
functions then mouse and real time key inputs, get line input, 
even scrollable areas and more.


Re: template ctor overload Segmentation fault

2021-12-14 Thread vit via Digitalmars-d-learn

On Tuesday, 14 December 2021 at 14:40:00 UTC, RazvanN 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)


PR: https://github.com/dlang/dmd/pull/13427


Thanks,

I got it to work for now:

```d
struct Foo(T){
this(Rhs, this This)(auto ref scope Rhs rhs)
if(__traits(isRef, rhs) == false){
}

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


struct Bar{
Foo!int foo;
}

void main(){
}

```


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

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

On Tuesday, 14 December 2021 at 17:20:18 UTC, chopchop wrote:

I am using the "ref" here (I put tinyurl to avoid 
over-referencing the post instead of the github page itself):

https://tinyurl.com/bdddkmub

I would like to be able to pass any kind of console to 
updateFoodToken ( Console c ), ie either a winconsole or a 
nixconsole, which are derived from Console.


I mean I probably have a cognitive bias of being a c++ dev. Let 
me explain. If I was coding in C++ I would pass "A&". Not 
"const A&", because I do two function calls with console - for 
example console.gotoxy(...) - but those 2 members functions are 
not suffixed "const". Since it is work in progress, I dont even 
know if I am going to modify those functions at the end or do 
something else with console...


Simple. Don't take a `ref`. Just take a `Console`. Classes in D 
are reference types, you're not making a copy as you would in C++ 
if you were to write `updateFoodToken(Console c)`.


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

2021-12-14 Thread chopchop 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


Hi Adam,

I am using the "ref" here (I put tinyurl to avoid 
over-referencing the post instead of the github page itself):

https://tinyurl.com/bdddkmub

I would like to be able to pass any kind of console to 
updateFoodToken ( Console c ), ie either a winconsole or a 
nixconsole, which are derived from Console.


I mean I probably have a cognitive bias of being a c++ dev. Let 
me explain. If I was coding in C++ I would pass "A&". Not "const 
A&", because I do two function calls with console - for example 
console.gotoxy(...) - but those 2 members functions are not 
suffixed "const". Since it is work in progress, I dont even know 
if I am going to modify those functions at the end or do 
something else with console...



But well, what do you guys think? The documentation does not even 
say if an "in" param is passed by value or reference ("may be 
passed by reference" it says). I don't really see how a copy of a 
console would work... Kind of eery in my minde.



Adam, I am actually using your code :) You and anyone else are 
welcome to review / send some Pull Request, deal with the console 
code, comment, etc





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

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

On Tuesday, 14 December 2021 at 05:38:17 UTC, Tejas wrote:

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`


Tejas, I think you should not read Adam's example as standalone, 
obviously he is implicitly reusing the definition of B in my 
first post, so B is indeed a child of A.


Re: Immutability and arrays

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

On 12/14/21 11:19 AM, Steven Schveighoffer wrote:

Er... scratch that, this isn't construction, it should use opAssign. 
Again, probably because memcpy+postblit is used by the runtime.


If not reported, it should be.


Simple proof that it is a bug:

```d
immutable (ComplexStruct)[] arr;
ComplexStruct[] arr2;

arr2[0] = arr[0]; // ok
arr2[] = arr[]; // error
```

If you can copy one element, you should be able to copy all the elements.

-Steve


Re: Immutability and arrays

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

On 12/14/21 11:14 AM, Steven Schveighoffer wrote:

On 12/14/21 10:53 AM, Stanislav Blinov wrote:

Now, since we have copy ctors, slice assignment should, ostensibly, 
attempt to copy-assign elements (i.e. absent opAssign, try the copy 
ctor first).


I agree slice-assign should work here with a copy ctor. What I think is 
happening is that it's still very much built on memcpy + postblit (so 
much of the array runtime is still magic functions).


postblit doesn't work because it first makes a copy of the data AS-IS, 
which means it's still immutable, and only after the postblit would it 
be mutable.


Er... scratch that, this isn't construction, it should use opAssign. 
Again, probably because memcpy+postblit is used by the runtime.


If not reported, it should be.

-Steve


Re: Immutability and arrays

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

On 12/14/21 10:53 AM, Stanislav Blinov wrote:

Now, since we have copy ctors, slice assignment should, ostensibly, 
attempt to copy-assign elements (i.e. absent opAssign, try the copy ctor 
first).


I agree slice-assign should work here with a copy ctor. What I think is 
happening is that it's still very much built on memcpy + postblit (so 
much of the array runtime is still magic functions).


postblit doesn't work because it first makes a copy of the data AS-IS, 
which means it's still immutable, and only after the postblit would it 
be mutable.


-Steve


Re: Immutability and arrays

2021-12-14 Thread Stanislav Blinov via Digitalmars-d-learn
On Tuesday, 14 December 2021 at 15:28:30 UTC, Steven 
Schveighoffer wrote:


All the other problems you are having are deriving from this 
problem.


Not exactly. One of the problems seems to be a genuine bug:

```d
struct S
{
int[] x;

// doesn't even participate here, neither would postblit
this(ref return scope inout S other)
{
x = other.x.dup;
}

void opAssign(ref return scope inout S other)
{
x = other.x.dup;
}
}

void main()
{
immutable(S)[] src = [S([1, 2]), S([3, 4])];

auto dst = new S[src.length];

//dst[0 .. $] = src[0 .. $]; // this fails to compile even 
with opAssign defined


// this works:
foreach (i, ref it; dst)
it = src[i];
}
```

Spec: https://dlang.org/spec/arrays.html#array-copying


...contents of the array are the target of the assignment...


Per that wording, slice assignment should perform the equivalent 
of that foreach loop (after overlap checks, etc.). It doesn't, 
just tries implicit conversion, and fails.


Now, since we have copy ctors, slice assignment should, 
ostensibly, attempt to copy-assign elements (i.e. absent 
opAssign, try the copy ctor first).


Re: Immutability and arrays

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

On 12/14/21 3:44 AM, rumbu wrote:
I am trying to understand why in this two different cases (Simple and 
Complex), the compiler behaviour is different.


```d
struct SimpleStruct { int x;}
struct ComplexStruct { int[] x; }

void main()
{
     SimpleStruct[] buf1;
     immutable(SimpleStruct)[] ibuf1;
     buf1[0 .. 10] = ibuf1[0 .. 10];
     //this works

     ComplexStruct[] buf2;
     immutable(ComplexStruct)[] ibuf2;

     buf2[0 .. 10] = ibuf2[0 .. 10];
     //error cannot implicitly convert expression `ibuf2[0..10]` of type 
`immutable(ComplexStruct)[]` to `ComplexStruct[]`

}
```




I know there have been several answers as to what the rules are, I want 
to answer why the rules are there.


In the first case, you have a simple struct which has a single integer 
in it. When copying that struct, you have no indirections (pointers), 
which means that adjusting the mutability is allowed:


```d
immutable s = SimpleStruct(5);
SimpleStruct s2 = s; // ok, we are making a copy of everything
```

In the second case, the `int[]` contains a pointer. So if you made a 
copy of that, you cannot change the mutability of the type, because now 
it would have a mutable pointer to immutable data:


```d
immutable s = ComplexStruct([5]);
ComplexStruct s2 = s; // error, cannot implicitly convert, there is an 
indirection

```

The WHY is this: let's say the above was allowed, `s2` is mutable, which 
means `s2.x` is mutable. Now I can do:


```d
s2.x[0] = 6;
```

And all of a sudden, immutable data has changed! This cannot be allowed, 
which is why you can't copy the struct.


All the other problems you are having are deriving from this problem.

-Steve


Re: Why code failed to compile for foo2?

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

On 12/14/21 12:04 AM, Tejas wrote:

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`?


Unqual is fine for value types, it should work in all cases.

The OP's problem is that it's entirely possible to build an overload set 
with *just* the unqualified types specified (in this case, an integral 
type), but there's not a way to express that and still have it work with 
IFTI.


In other words, if you have a call like:

```d
const int x;
foo2(x);
```

You want to have the parameter be mutable inside foo2. There currently 
isn't a way to express that if `foo2` is an IFTI template. The opposite 
is actually easily expressable:


```d
void foo2(T)(const(T) val)
{
   // only one instantiation of foo2 per const(int), immutable(int), int,
   // and now val is const, even if the argument is not
}
```

With a standard function it works just fine due to implicit conversion, 
but with IFTI, there's no way to express it because it goes through an 
alias. The closest you can come is to write a wrapper shim that calls 
the right instantiation. This should be OK as long as inlining is 
happening, but it seems like extra work for the optimizer, when it 
should be easy to express in the language somehow.


BTW, there is a related issue: https://issues.dlang.org/show_bug.cgi?id=1807

-Steve


Re: template ctor overload Segmentation fault

2021-12-14 Thread RazvanN 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)


PR: https://github.com/dlang/dmd/pull/13427


Re: template ctor overload Segmentation fault

2021-12-14 Thread RazvanN via Digitalmars-d-learn

On Tuesday, 14 December 2021 at 13:02:16 UTC, Tejas wrote:

On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote:

[...]


Then why did my modification work?

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

this(scope Foo!(T)* rhs){ //replaced typeof(this) with 
Foo!T and ref with pointer. Code still works if I retain 
typeof(this)

}
}


struct Bar{
Foo!int foo;
}

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

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

Did my modifications ensure that this is not treated as a copy 
constructor?


Yes, the copy constructor needs to be explicitly defined by 
passing a ref parameter. Since you are expecting an explicit 
pointer, the compiler does not see it as a copy constructor and 
therefore does not try to generate one for Bar.


Re: Why code failed to compile for foo2?

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

On Tuesday, 14 December 2021 at 05:04:46 UTC, Tejas wrote:

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`?


1. A template function should behave as to replace 4 overload 
functions

There is special logic for parameter type (2 vs 4...)

2. Your implementation does not remove 'const' as below
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

pragma(msg, T.stringof);
writeln(x);
}

void main()
{
import std.math;

const int s1 = -3;
int s2 = -2;
foo2(abs(s1));
foo2(abs(s2));

enum byte b1 = 0;
const byte b2;
byte b3;
foo2(b1);
foo2(b2);
foo2(b3);
}
--Output
const(int)
int
byte
const(byte)
3
2
0
0
0



Re: Immutability and arrays

2021-12-14 Thread rumbu via Digitalmars-d-learn
On Tuesday, 14 December 2021 at 12:13:23 UTC, Stanislav Blinov 
wrote:


Because is(typeof(immutable(ComplexStruct).x) == 
immutable(int[])). Can't bind an array of immutable to array of 
mutable. This would require a deep copy, i.e. copy constructor.


This means that the only way to write a generic function which 
copies an array of immutable elements to another array is this:


```d
void copy10(T)(T[] dst, immutable(T)[] src)
{
static if (is(immutable(T): T))
dst[0..10] = src[0..10];
 else
dst[0..10] = cast(T[])src[0..10]; // or better a deep 
copy

}
```

Btw, tried to give ComplexStruct a some copy constructors 
(casting away immutable is just for the example, I know it's not 
the way to do it).


```d
struct ComplexStruct
{
   int[] x;

   this(ref return scope ComplexStruct another)
   {
   this.x = another.x;
   }

   this(ref return scope immutable(ComplexStruct) another)
   {
   this.x = cast(int[])(another.x);
   }
}
```

Still slice assignment does not work. I think I will drop 
immutability, it's too complicated to work with.





Re: template ctor overload Segmentation fault

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

On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote:

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

[...]


The problem is that the compiler will try to generate an inout 
copy constructor for Bar that looks roughly like this:


```
this(ref scope inout(Bar) p) inout
{
this.foo = p;
}
```

The idea behind this lowering is to try and call the copy 
constructor for Foo object if possible. One issue here is that 
copy constructors have the same symbol name as constructors 
(__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`.
Since both the instance and the parameter are inout, the copy 
constructor of Foo cannot be called, so the templated 
constructor is called. After generating the template instance 
of the constructor, you end up with `this(scope inout(Foo)) 
inout` ; that is basically an rvalue constructor. This is not 
valid code; if you write:


```
struct Foo(T){
//this(Rhs, this This)(scope Rhs rhs){}
this(scope inout(Foo!int) rhs) inout {}

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

You will get an error stating that you cannot define both an 
rvalue constructor and a copy constructor. However, since the 
constructor is templated it is impossible for the compiler to 
issue this error before actually instantiating the constructor. 
I see 2 possible fixes for this: (1) either we rename the copy 
constructor symbol to __cpCtor so that it does not clash with 
the normal constructor overload set or (2) when a templated 
constructor is instantiated, we can check whether it is an 
rvalue constructor and issue an error if a copy constructor 
exists.


When I implemented the copy constructor I thought that it would 
better to have the copy constructor on a different overload set 
than the normal constructors, however, Walter insisted that 
they have the same name. So, I guess (2) is the way to go.


Cheers,
RazvanN


Then why did my modification work?

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

this(scope Foo!(T)* rhs){ //replaced typeof(this) with Foo!T 
and ref with pointer. Code still works if I retain typeof(this)

}
}


struct Bar{
Foo!int foo;
}

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

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

Did my modifications ensure that this is not treated as a copy 
constructor?


Re: Immutability and arrays

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

On Tuesday, 14 December 2021 at 08:44:02 UTC, rumbu wrote:
I am trying to understand why in this two different cases 
(Simple and Complex), the compiler behaviour is different.


```d
struct SimpleStruct { int x;}
struct ComplexStruct { int[] x; }

void main()
{
SimpleStruct[] buf1;
immutable(SimpleStruct)[] ibuf1;
buf1[0 .. 10] = ibuf1[0 .. 10];
//this works

ComplexStruct[] buf2;
immutable(ComplexStruct)[] ibuf2;

buf2[0 .. 10] = ibuf2[0 .. 10];
//error cannot implicitly convert expression `ibuf2[0..10]` 
of type `immutable(ComplexStruct)[]` to `ComplexStruct[]`

}
```


Because is(typeof(immutable(ComplexStruct).x) == 
immutable(int[])). Can't bind an array of immutable to array of 
mutable. This would require a deep copy, i.e. copy constructor.


Re: Immutability and arrays

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

On Tuesday, 14 December 2021 at 08:44:02 UTC, rumbu wrote:
I am trying to understand why in this two different cases 
(Simple and Complex), the compiler behaviour is different.


```d
struct SimpleStruct { int x;}
struct ComplexStruct { int[] x; }

void main()
{
SimpleStruct[] buf1;
immutable(SimpleStruct)[] ibuf1;
buf1[0 .. 10] = ibuf1[0 .. 10];
//this works

ComplexStruct[] buf2;
immutable(ComplexStruct)[] ibuf2;

buf2[0 .. 10] = ibuf2[0 .. 10];
//error cannot implicitly convert expression `ibuf2[0..10]` 
of type `immutable(ComplexStruct)[]` to `ComplexStruct[]`

}
```


there are special cases in the compiler for values that have no 
mutable indirections: 
https://dlang.org/spec/const3.html#implicit_qualifier_conversions


Values that have no mutable indirections (including structs 
that don't contain any field with mutable indirections) can be 
implicitly converted across mutable, const, immutable, const 
shared, inout and inout shared.


so that first struct may be implicitly converted between 
mutable/immutable/const because it doesn't contain any mutable 
indirections (mutable arrays/pointers/references)


Re: template ctor overload Segmentation fault

2021-12-14 Thread RazvanN 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)


The problem is that the compiler will try to generate an inout 
copy constructor for Bar that looks roughly like this:


```
this(ref scope inout(Bar) p) inout
{
this.foo = p;
}
```

The idea behind this lowering is to try and call the copy 
constructor for Foo object if possible. One issue here is that 
copy constructors have the same symbol name as constructors 
(__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`.
Since both the instance and the parameter are inout, the copy 
constructor of Foo cannot be called, so the templated constructor 
is called. After generating the template instance of the 
constructor, you end up with `this(scope inout(Foo)) inout` ; 
that is basically an rvalue constructor. This is not valid code; 
if you write:


```
struct Foo(T){
//this(Rhs, this This)(scope Rhs rhs){}
this(scope inout(Foo!int) rhs) inout {}

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

You will get an error stating that you cannot define both an 
rvalue constructor and a copy constructor. However, since the 
constructor is templated it is impossible for the compiler to 
issue this error before actually instantiating the constructor. I 
see 2 possible fixes for this: (1) either we rename the copy 
constructor symbol to __cpCtor so that it does not clash with the 
normal constructor overload set or (2) when a templated 
constructor is instantiated, we can check whether it is an rvalue 
constructor and issue an error if a copy constructor exists.


When I implemented the copy constructor I thought that it would 
better to have the copy constructor on a different overload set 
than the normal constructors, however, Walter insisted that they 
have the same name. So, I guess (2) is the way to go.


Cheers,
RazvanN


Re: A debug class has started

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

On Tuesday, 14 December 2021 at 08:07:43 UTC, WebFreak001 wrote:


The best way would be not doing this at all - when you 
manipulate strings/arrays in D you can do so by just assigning 
the elements like this:


```d
immutable(char)[] replaceChar(char[] str, 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 str.idup;
}
```

then when you call it:
```d
replaceChar(str.dup, ';', 'X');
```

or the function more idiomatically:
```d
string replaceChar(scope char[] str, char ch1, char ch2)
{
// ref makes the `c` variable an l-value / assignable and 
modifies the character when assigned

foreach (i, ref c; str)
{
if (c == ch1)
{
writefln("Found %s at str[%s]", c, i);
c = ch2;
}
}

return str.idup; // you could also not .idup and return 
char[] and let the caller .idup it when needed

}
```

You only really need to work with pointers when you interface 
with a C library that needs them.


This was of course just me 'playing around with pointer casting 
in D', and not code that I would have deployed. Debugging that 
code used up an hour of my life .. that I cannot get back


I might try out @safe instead ;-)





Immutability and arrays

2021-12-14 Thread rumbu via Digitalmars-d-learn
I am trying to understand why in this two different cases (Simple 
and Complex), the compiler behaviour is different.


```d
struct SimpleStruct { int x;}
struct ComplexStruct { int[] x; }

void main()
{
SimpleStruct[] buf1;
immutable(SimpleStruct)[] ibuf1;
buf1[0 .. 10] = ibuf1[0 .. 10];
//this works

ComplexStruct[] buf2;
immutable(ComplexStruct)[] ibuf2;

buf2[0 .. 10] = ibuf2[0 .. 10];
//error cannot implicitly convert expression `ibuf2[0..10]` 
of type `immutable(ComplexStruct)[]` to `ComplexStruct[]`

}
```




Re: How to define property type to Array!struct?

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

On Tuesday, 14 December 2021 at 08:12:04 UTC, zoujiaqing wrote:

My code:

```D
module http.HttpRequest;

import std.container;
import std.array : Appender;

struct HttpRequest
{
struct Header()
{
Appender!string name;
Appender!string value;
}

string method;
string uri;
int versionMajor = 0;
int versionMinor = 0;
Array!Header headers;
ubyte[] content;
bool keepAlive = false;
}
```

Error code:
```D
source/http/HttpRequest.d(18,5): Error: struct 
`std.container.array.Array` does not match any template 
declaration

```


the problem is that your header is a template, so you need to 
instantiate it:

```d
Array!(Header!()) headers;
```

the error message is kinda poor here.

Alternatively, remove the template `()` from your `struct Header`


How to define property type to Array!struct?

2021-12-14 Thread zoujiaqing via Digitalmars-d-learn

My code:

```D
module http.HttpRequest;

import std.container;
import std.array : Appender;

struct HttpRequest
{
struct Header()
{
Appender!string name;
Appender!string value;
}

string method;
string uri;
int versionMajor = 0;
int versionMinor = 0;
Array!Header headers;
ubyte[] content;
bool keepAlive = false;
}
```

Error code:
```D
source/http/HttpRequest.d(18,5): Error: struct 
`std.container.array.Array` does not match any template 
declaration

```


Re: A debug class has started

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

On Monday, 13 December 2021 at 22:43:14 UTC, forkit wrote:

[...]

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


note:


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


this is also undefined behavior (toStringz returns an 
immutable(char)* which you cast away)



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


this is a C library function - this is risky if your string is 
not a string literal (may copy too much or segfault) - I would 
recommend not using this. This will only work properly when you 
have string literals (strings that are created using `""` in 
code, no other strings like those that are for example read from 
user input, from files or dynamically created)



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

[...]


the last two here are equivalent, I personally prefer the last 
one. I think these are the idiomatic way how to duplicate a 
string into writable memory and get the pointer to it.


The best way would be not doing this at all - when you manipulate 
strings/arrays in D you can do so by just assigning the elements 
like this:


```d
immutable(char)[] replaceChar(char[] str, 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 str.idup;
}
```

then when you call it:
```d
replaceChar(str.dup, ';', 'X');
```

or the function more idiomatically:
```d
string replaceChar(scope char[] str, char ch1, char ch2)
{
// ref makes the `c` variable an l-value / assignable and 
modifies the character when assigned

foreach (i, ref c; str)
{
if (c == ch1)
{
writefln("Found %s at str[%s]", c, i);
c = ch2;
}
}

return str.idup; // you could also not .idup and return 
char[] and let the caller .idup it when needed

}
```

You only really need to work with pointers when you interface 
with a C library that needs them.