www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What is special about an immutable array of class objects, and why can

reply James Blachly <james.blachly gmail.com> writes:
Consider the below:

```
class C
{
     int x;
}

struct S
{
     int x;
}


void main()
{
	immutable C[] c = [ new C(), new C()];
	immutable S[] s = [ S(), S() ];
     immutable int[] i = [ 1, 2 ];

     auto x = c.dup;
     auto y = s.dup;
     auto z = i.dup;

}
```

This fails to compile with a `.dup` template matching error at 
line `auto x = c.dup;`. However, calling `.idup` works just fine. 
The immutable struct array and int array of course `.dup` just 
fine.

I would have guessed that changing the definition of `C[]` to 
`immutable(C)[]` would have also helped, but it did not.

Why are the class objects special in this case, and why does 
`immutable(C)[]` not help?   I believed that this defined a 
dynamic array `c` which was itself mutable, the elements of which 
were immutable.

Thanks for insights.
May 28 2018
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, May 28, 2018 13:51:49 James Blachly via Digitalmars-d-learn 
wrote:
 Consider the below:

 ```
 class C
 {
      int x;
 }

 struct S
 {
      int x;
 }


 void main()
 {
   immutable C[] c = [ new C(), new C()];
   immutable S[] s = [ S(), S() ];
      immutable int[] i = [ 1, 2 ];

      auto x = c.dup;
      auto y = s.dup;
      auto z = i.dup;

 }
 ```

 This fails to compile with a `.dup` template matching error at
 line `auto x = c.dup;`. However, calling `.idup` works just fine.
 The immutable struct array and int array of course `.dup` just
 fine.

 I would have guessed that changing the definition of `C[]` to
 `immutable(C)[]` would have also helped, but it did not.

 Why are the class objects special in this case, and why does
 `immutable(C)[]` not help?   I believed that this defined a
 dynamic array `c` which was itself mutable, the elements of which
 were immutable.

 Thanks for insights.
dup makes the entire thing mutable, and the compiler can't safely convert immutable class references to mutable ones. And when you think about it, the immutability of the array itself really isn't the key thing here anyway. All you have to do to get a mutable one is to slice it - slicing gives you a tail-const/tail-immutable dynamic array pointing to the same data. So, ultimately, what you're doing with dup vs idup is deciding what the mutability of the elements is. dup makes them mutable, and idup makes them immutable. In the case of primitive types or structs which don't have postblit constructors, that's usually trivial, but it doesn't work with class references. For them, you're stuck with the same level of mutablity, because there is no easy conversion for them between mutable and immmutable. - Jonathan M Davis
May 28 2018
prev sibling next sibling parent bauss <jj_1337 live.dk> writes:
On Monday, 28 May 2018 at 13:51:49 UTC, James Blachly wrote:
 Consider the below:

 ```
 class C
 {
     int x;
 }

 struct S
 {
     int x;
 }


 void main()
 {
 	immutable C[] c = [ new C(), new C()];
 	immutable S[] s = [ S(), S() ];
     immutable int[] i = [ 1, 2 ];

     auto x = c.dup;
     auto y = s.dup;
     auto z = i.dup;

 }
 ```

 This fails to compile with a `.dup` template matching error at 
 line `auto x = c.dup;`. However, calling `.idup` works just 
 fine. The immutable struct array and int array of course `.dup` 
 just fine.

 I would have guessed that changing the definition of `C[]` to 
 `immutable(C)[]` would have also helped, but it did not.

 Why are the class objects special in this case, and why does 
 `immutable(C)[]` not help?   I believed that this defined a 
 dynamic array `c` which was itself mutable, the elements of 
 which were immutable.

 Thanks for insights.
I'm going to make a wild guess that .dup is a shallow copy and if the class has any members that are reference types only references to them are copied. Which means that by creating a mutable duplicate of the class you essentially have a mutable reference to said member. Even though in your example that isn't the case, then that's the only reason I can think of the restriction making sense.
May 28 2018
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/28/18 9:51 AM, James Blachly wrote:

 Why are the class objects special in this case, and why does 
 `immutable(C)[]` not help?   I believed that this defined a dynamic 
 array `c` which was itself mutable, the elements of which were immutable.
To build on what others have said, the key thing you are missing is that every instance of C is a *reference*. So you essentially have an array of pointers. If you dup the array, you are not duplicating the class instances, each element of the array still points at the same instances! So naturally, you can't have both a mutable and immutable reference to the same instance. This is easily demonstrated: auto c = [new C(), new C()]; c[0].x = 5; auto c2 = c.dup; c2[0].x = 6; writeln(c[0].x); // 6 Contrast that with the struct and int arrays, where the *entire contents* are copied. Hope that helps. -Steve
May 28 2018