Copying with immutable arrays

2012-10-27 Thread Tobias Pankrath
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?


Re: Copying with immutable arrays

2012-10-27 Thread Ali Çehreli

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


Re: Copying with immutable arrays

2012-10-28 Thread Tobias Pankrath

Thank you for your detailed answer!

What I don't understand is the reason why you need the .dup in 
the first place.


Take a look at these two structs that now contain an int* and an 
int instead of string[].


struct SA {
int i;
}

struct SB {
int* i;
}

If you try to .dup an array of SA it will work and if you .dup an 
array of SB it will fail. I understand why it works this way, 
because in case of SB you would get an mutable reference of type 
int* out of immutable(int*), which would brake the type system. 
However the struct SwA from above does neither correspond to SA 
nor to SB, it's imo more like SC:


struct SC {
immutable(int)* i;
}

Now a copy would do no harm, everything that was immutable in the 
source and is still accessable from the copy is immutable, too. 
Any reason (despite of implemenational issues) that this is not 
how it works?





Re: Copying with immutable arrays

2012-10-28 Thread Ali Çehreli

On 10/28/2012 02:37 AM, Tobias Pankrath wrote:
> the struct
> SwA from above does neither correspond to SA nor to SB, it's imo more
> like SC:
>
> struct SC {
> immutable(int)* i;
> }

Just to confirm, the above indeed works:

struct SC {
immutable(int)* i;
}

void main()
{
immutable(SC)[] arr1;
SC[] arr2 = arr1.dup;// compiles
}

> Now a copy would do no harm, everything that was immutable in the source
> and is still accessable from the copy is immutable, too. Any reason
> (despite of implemenational issues) that this is not how it works?

Getting back to the original code, the issue boils down to whether we 
can copy imutable(string[]) to string[]:


import std.stdio;

struct SwA {
string[] strings;
}

void main()
{
immutable(SwA)[] arr1;
writeln(typeid(arr1[0].strings));
}

The program prints the following:

immutable(immutable(immutable(char)[])[])

Translating the innermost definition as string:

immutable(immutable(string)[])

Let's remove the struct and look at a variable the same type as the member:

immutable(string[]) imm = [ "a", "b" ];
writeln(typeid(imm));

The typeid is the same:

immutable(immutable(immutable(char)[])[])

So we can concentrate on 'imm' for this exercise. This is the same 
compilation error:


immutable(string[]) imm = [ "aaa", "bbb" ];
string[] mut = imm;   // <-- compilation ERROR

If that compiled, then both 'imm' and 'mut' would be providing access to 
the same set of strings. But the problem is, 'mut' could replace those 
strings (note that it could not modify the characters of those strings, 
but it could replace the whole string):


mut[0] = "hello";

That would effect 'imm' as well. ('imm' is the equivalent of SwA.strings 
from your original code.)


Ali



Re: Copying with immutable arrays

2012-10-29 Thread Tobias Pankrath

On Monday, 29 October 2012 at 06:19:36 UTC, Ali Çehreli wrote:


Just to confirm, the above indeed works:

struct SC {
immutable(int)* i;
}

void main()
{
immutable(SC)[] arr1;
SC[] arr2 = arr1.dup;// compiles
}


Oh, I thought I've tried it.


[snip] [Really detailed description here] [snip]


Thanks, now I've got it :-)


Re: Copying with immutable arrays

2012-10-30 Thread Don Clugston

On 29/10/12 07:19, Ali Çehreli wrote:

On 10/28/2012 02:37 AM, Tobias Pankrath wrote:
 > the struct
 > SwA from above does neither correspond to SA nor to SB, it's imo more
 > like SC:
 >
 > struct SC {
 > immutable(int)* i;
 > }

Just to confirm, the above indeed works:

struct SC {
 immutable(int)* i;
}

void main()
{
 immutable(SC)[] arr1;
 SC[] arr2 = arr1.dup;// compiles
}

 > Now a copy would do no harm, everything that was immutable in the source
 > and is still accessable from the copy is immutable, too. Any reason
 > (despite of implemenational issues) that this is not how it works?

Getting back to the original code, the issue boils down to whether we
can copy imutable(string[]) to string[]:

import std.stdio;

struct SwA {
 string[] strings;
}

void main()
{
 immutable(SwA)[] arr1;
 writeln(typeid(arr1[0].strings));
}

The program prints the following:

immutable(immutable(immutable(char)[])[])

Translating the innermost definition as string:

immutable(immutable(string)[])

Let's remove the struct and look at a variable the same type as the member:

 immutable(string[]) imm = [ "a", "b" ];
 writeln(typeid(imm));

The typeid is the same:

immutable(immutable(immutable(char)[])[])

So we can concentrate on 'imm' for this exercise. This is the same
compilation error:

 immutable(string[]) imm = [ "aaa", "bbb" ];
 string[] mut = imm;   // <-- compilation ERROR

If that compiled, then both 'imm' and 'mut' would be providing access to
the same set of strings. But the problem is, 'mut' could replace those
strings (note that it could not modify the characters of those strings,
but it could replace the whole string):

 mut[0] = "hello";

That would effect 'imm' as well. ('imm' is the equivalent of SwA.strings
from your original code.)

Ali


Awesome answer, it's these kinds of responses that make the D community 
so great.