Thread overview
What is special about an immutable array of class objects, and why can I not .dup ?
May 28, 2018
James Blachly
May 28, 2018
Jonathan M Davis
May 28, 2018
bauss
May 28, 2018
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
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
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
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