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: 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: 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: 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)


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[]`

}
```