www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - insertInPlace differences between compilers

reply "John McFarlane" <dlang john.mcfarlane.name> writes:
I'm trying to write a struct template that uses `insertInPlace`. 
However, it doesn't work with certain template type / compiler 
combinations. Consider the following:

     import std.range;
     struct S { const int c; }
     S[] a;
     insertInPlace(a, 0, S());

With DMD64 D Compiler v2.066.1, I get the following error:
/usr/include/dmd/phobos/std/array.d(1013): Error: cannot modify 
struct dest[i] S with immutable members
/usr/include/dmd/phobos/std/array.d(1079): Error: template 
instance std.array.copyBackwards!(S) error instantiating
./d/my_source_file.d(12345):        instantiated from here: 
insertInPlace!(S, S)

But with gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1), the same 
code compiles.

While I'm still trying to get to grips with mutability in D, I 
wonder which compiler/library's got it right or whether this is a 
difference in language versions. The error still occurs when I 
change the type of `c` to a const class which is the case I'd 
really like this to work for.

I can avoid `insertInPlace` on DMD with the following, much 
slower alternative:

     a = a[0..insertionPoint] ~ element ~ a[insertionPoint..$];

In the short term, could anybody suggest a `static if` expression 
to determine whether I can copy the type to the satisfaction of 
`copyBackwards`? I tried isMutable but that didn't seem to work.

Thanks, John
Nov 11 2014
parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 11 November 2014 at 20:53:51 UTC, John McFarlane 
wrote:
 I'm trying to write a struct template that uses 
 `insertInPlace`. However, it doesn't work with certain template 
 type / compiler combinations. Consider the following:

     import std.range;
     struct S { const int c; }
     S[] a;
     insertInPlace(a, 0, S());

 With DMD64 D Compiler v2.066.1, I get the following error:
 /usr/include/dmd/phobos/std/array.d(1013): Error: cannot modify 
 struct dest[i] S with immutable members
 /usr/include/dmd/phobos/std/array.d(1079): Error: template 
 instance std.array.copyBackwards!(S) error instantiating
 ./d/my_source_file.d(12345):        instantiated from here: 
 insertInPlace!(S, S)
I believe DMD is correct here and here is why: While the function is called "insert" the operation is actually an assignment. DMD initializes all arrays elements to the default value so your array position 0 actually contains an S already. This means the operation is equivalent to auto b = S(); b = S(); Since S is a value type you're actually making a modification 'c' as stored in 'b'. The compiler is unable to prove that there is no other reference to that same memory location (though in this case the variable is on the stack and the modification is local so such knowledge may be possible).
 In the short term, could anybody suggest a `static if` 
 expression to determine whether I can copy the type to the 
 satisfaction of `copyBackwards`? I tried isMutable but that 
 didn't seem to work.

 Thanks, John
You probably want std.traits.isAssignable pragma(msg, isAssignable!(S, S)); // False
Nov 11 2014
parent reply "John McFarlane" <dlang john.mcfarlane.name> writes:
On Wednesday, 12 November 2014 at 00:31:31 UTC, Jesse Phillips 
wrote:
 On Tuesday, 11 November 2014 at 20:53:51 UTC, John McFarlane 
 wrote:
 I'm trying to write a struct template that uses 
 `insertInPlace`. However, it doesn't work with certain 
 template type / compiler combinations. Consider the following:

    import std.range;
    struct S { const int c; }
    S[] a;
    insertInPlace(a, 0, S());

 With DMD64 D Compiler v2.066.1, I get the following error:
 /usr/include/dmd/phobos/std/array.d(1013): Error: cannot 
 modify struct dest[i] S with immutable members
 /usr/include/dmd/phobos/std/array.d(1079): Error: template 
 instance std.array.copyBackwards!(S) error instantiating
 ./d/my_source_file.d(12345):        instantiated from here: 
 insertInPlace!(S, S)
I believe DMD is correct here and here is why: While the function is called "insert" the operation is actually an assignment. DMD initializes all arrays elements to the default value so your array position 0 actually contains an S already. This means the operation is equivalent to auto b = S(); b = S(); Since S is a value type you're actually making a modification 'c' as stored in 'b'. The compiler is unable to prove that there is no other reference to that same memory location (though in this case the variable is on the stack and the modification is local so such knowledge may be possible).
That makes sense. In the case that `c` is a class, do you think I'd have any luck if I made it immutable?
 In the short term, could anybody suggest a `static if` 
 expression to determine whether I can copy the type to the 
 satisfaction of `copyBackwards`? I tried isMutable but that 
 didn't seem to work.

 Thanks, John
You probably want std.traits.isAssignable pragma(msg, isAssignable!(S, S)); // False
That's exactly what I was looking for. Thank you.
Nov 12 2014
parent reply "John McFarlane" <dlang john.mcfarlane.name> writes:
On Wednesday, 12 November 2014 at 19:15:24 UTC, John McFarlane 
wrote:
 On Wednesday, 12 November 2014 at 00:31:31 UTC, Jesse Phillips 
 wrote:
 On Tuesday, 11 November 2014 at 20:53:51 UTC, John McFarlane 
 wrote:
 I'm trying to write a struct template that uses 
 `insertInPlace`. However, it doesn't work with certain 
 template type / compiler combinations. Consider the following:

   import std.range;
   struct S { const int c; }
   S[] a;
   insertInPlace(a, 0, S());

 With DMD64 D Compiler v2.066.1, I get the following error:
 /usr/include/dmd/phobos/std/array.d(1013): Error: cannot 
 modify struct dest[i] S with immutable members
 /usr/include/dmd/phobos/std/array.d(1079): Error: template 
 instance std.array.copyBackwards!(S) error instantiating
 ./d/my_source_file.d(12345):        instantiated from here: 
 insertInPlace!(S, S)
I believe DMD is correct here and here is why: While the function is called "insert" the operation is actually an assignment. DMD initializes all arrays elements to the default value so your array position 0 actually contains an S already. This means the operation is equivalent to auto b = S(); b = S(); Since S is a value type you're actually making a modification 'c' as stored in 'b'. The compiler is unable to prove that there is no other reference to that same memory location (though in this case the variable is on the stack and the modification is local so such knowledge may be possible).
That makes sense. In the case that `c` is a class, do you think I'd have any luck if I made it immutable?
The quick answer is that it doesn't help. DMD still doesn't like me using insertInPlace. This is a little disappointing as immutable is supposed to avoid the need for copying. Then again, I guess that's a compiler - not language - level affordance. Thanks again.
 In the short term, could anybody suggest a `static if` 
 expression to determine whether I can copy the type to the 
 satisfaction of `copyBackwards`? I tried isMutable but that 
 didn't seem to work.

 Thanks, John
You probably want std.traits.isAssignable pragma(msg, isAssignable!(S, S)); // False
That's exactly what I was looking for. Thank you.
Nov 12 2014
parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Wednesday, 12 November 2014 at 19:25:49 UTC, John McFarlane 
wrote:
 That makes sense. In the case that `c` is a class, do you 
 think I'd have any luck if I made it immutable?
The quick answer is that it doesn't help. DMD still doesn't like me using insertInPlace. This is a little disappointing as immutable is supposed to avoid the need for copying. Then again, I guess that's a compiler - not language - level affordance. Thanks again.
Consider this code: void main() { import std.range; class C { string name; this(string n) { name = n; }} struct S { C c; } S a = S(new C("a")); S b = S(new C("b")); auto pC = &b.c; b = a; assert(pC.name == "a"); assert(b.c.name == "a"); } I have removed the compiler guarantee of not modifying c. What you'll notice here is that I've taken a pointer to a memory location in your struct after assigning to the struct that memory location has been modified to reflect the new class object. Had the compiler allowed this with the immutable c, by not performing a copy, then the assert would have failed which makes no sense as you wanted to store 'a' in that memory location.
Nov 12 2014