Copying with immutable arrays

Ali Çehreli acehreli at yahoo.com
Sat Oct 27 08:29:34 PDT 2012


On 10/27/2012 02:30 AM, Tobias Pankrath wrote:
> So I have this immutable array with user defined structs but I can not
> make a copy from it.
>
> See:
>
> struct SwA {
> string[] strings;
> }
>
> void main()
> {
> immutable(SwA)[] arr1;
> SwA[] arr2 = arr1.dup;
> }
>
> Says:
> Error: cannot implicitly convert element type immutable(SwA) to mutable
> in arr1.dup
>
> Next try:
>
> struct SwA {
> string[] strings;
> }
>
> void main()
> {
> import std.algorithm;
> immutable(SwA)[] arr1;
> SwA[] arr2;
> copy(arr1, arr2);
> }
>
> Says:
> test.d(11): Error: template std.algorithm.copy does not match any
> function template declaration
> /home/tobias/projekte/d/dmd/src/../../phobos/std/algorithm.d(5859):
> Error: template std.algorithm.copy(Range1,Range2) if
> (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1)))
> cannot deduce template function from argument types
> !()(immutable(SwA)[],SwA[])
>
> (Which is a bug, I guess).
>
> So can I do this without a cast?

Casting may not do the right thing, as the immutable object would be 
confused if the mutable object modify members.

Copying a struct produces an object of its own type. If the original is 
an immutable SwA, then the copy is an immutable SwA. That's why the 
compiler cannot produce a mutable SwA automatically.

After the naming convention of arrays, objects can be copied by an 
explicit dup() function:

struct SwA {
     string[] strings;

     SwA dup() const @property
     {
         auto result = SwA(strings.dup);
         return result;
     }
}

(Apologies if the following is obvious after that.)

Now the following compiles:

     auto i = immutable(SwA)([ "a", "b" ]);
     SwA m = i.dup;

And as expected, the following would compile as well:

     m.strings ~= "c";

With that, to produce mutable elements from an array of immutable(SwA), 
we can use map() and if the mutable elements need not be put into an 
array eagerly, the following is sufficient:

     auto arr1 = [ immutable(SwA)([ "a", "b" ]),
                   immutable(SwA)([ "x", "y" ]) ];

     auto arr2 = arr1.map!(e => e.dup);
     writeln(arr2);

arr2 is a range of mutable SwA objects that can be passed to other range 
algorithms, even to writeln. (I am pretty sure the produced SwA objects 
are rvalues as they come out of map.)

The output is:

[SwA(["a", "b"]), SwA(["x", "y"])]

And of course, if needed, arr2 could have been an actual array by 
calling array():

import std.array;
// ...
     auto arr2 = arr1.map!(e => e.dup).array;

Here is the whole program:

struct SwA {
     string[] strings;

     SwA dup() const @property
     {
         auto result = SwA(strings.dup);
         return result;
     }
}

import std.stdio;
import std.algorithm;
import std.array;

void main()
{
     auto i = immutable(SwA)([ "a", "b" ]);
     SwA m = i.dup;
     m.strings ~= "c";

     auto arr1 = [ immutable(SwA)([ "a", "b" ]),
                   immutable(SwA)([ "x", "y" ]) ];

     auto arr2 = arr1.map!(e => e.dup);
     writeln(arr2);
}

Ali


More information about the Digitalmars-d-learn mailing list