digitalmars.D.learn - Simple immutable example doesn't work - why???
- Louis Berube (23/23) Nov 11 2013 Simple example:
- Louis Berube (23/23) Nov 11 2013 Edit for (hopefully) better readability:
- Dicebot (2/4) Nov 11 2013 auto t = new immutable Test(4);
- Louis Berube (27/27) Nov 11 2013 Thanks, I think I understand. Now, how about an array of
- TheFlyingFiddle (40/42) Nov 11 2013 Well when you create an immutable array you cannot change any of
- TheFlyingFiddle (4/13) Nov 11 2013 Plz ignore my pervious statment. I guess i'm to tiered atm i take
- TheFlyingFiddle (38/40) Nov 11 2013 I rly am to tiered to think straight. Ingore the ignore post. I
- Kenji Hara (61/88) Nov 12 2013 Once you initialize an immutable class reference, you won't be
- Louis Berube (18/18) Nov 12 2013 Thanks to both TFF and Kenji for their excellent explanations. I
- Dicebot (23/28) Nov 13 2013 Both yes and now. You are correct that those are two observable
- Rene Zwanenburg (5/23) Nov 13 2013 There's a Rebindable template in Phobos which I think does what
- TheFlyingFiddle (21/44) Nov 11 2013 Well the issue is that new Test(5) is not an immutable object.
Simple example: // file immutable_example.d immutable class Test { public: this(in uint value) { this.value = value; } unittest { auto t = new Test(4); // "Error: immutable method // immutable_example.Test.this is not // callable using a mutable object" assert (t.value == 4); } private: uint value; } Assuming this is not a compiler issue, what am I missing? Integer literal is about as immutable as it gets.
Nov 11 2013
Edit for (hopefully) better readability: Simple example: // file immutable_example.d immutable class Test { public: this(in uint value) { this.value = value; } unittest { auto t = new Test(4); // "Error: immutable method // immutable_example.Test.this // is not callable using // a mutable object" assert (t.value == 4); } private: uint value; } Assuming this is not a compiler issue, what am I missing? Integer literal is about as immutable as it gets.
Nov 11 2013
On Tuesday, 12 November 2013 at 00:43:34 UTC, Louis Berube wrote:Assuming this is not a compiler issue, what am I missing? Integer literal is about as immutable as it gets.auto t = new immutable Test(4);
Nov 11 2013
Thanks, I think I understand. Now, how about an array of immutables: immutable class Test { public: this(in uint value) { this.value = value; } unittest { auto t = new immutable Test(4); assert (t.value == 4); } unittest { auto tarray = new immutable(Test)[3]; tarray[0] = new immutable Test(4); // "Error: cannot modify // immutable expression // tarray[0]" } private: uint value; } I thought the parantheses in the array declaration would do the trick, but apparently not.
Nov 11 2013
On Tuesday, 12 November 2013 at 01:15:02 UTC, Louis Berube wrote:I thought the parantheses in the array declaration would do the trick, but apparently not.Well when you create an immutable array you cannot change any of the elements in the array. I'm guessing what you want is a mutable array that contains immutable objects. I don't think you can create such an array in D (i am not sure though i doubt that it would be usefull anyhow) However if you want to build a mutable array and then make the entire structure immutable do something like this. class Test { private uint value; //Ctor needs to be immutable to create immutable objects. this(uint value) immutable { this.value = value; } //We need this to be able to construct initially mutable objects. this(uint value) { this.value = value; } } unittest { auto array = buildTests(5); } immutable(Test)[] buildTests(uint num) { import std.exception : assumeUnique; auto array = new Test[num]; foreach(i; 0 .. num) { array[i] = new Test(i); } //Since we hold the only value that can be mutated //here its ok to assume that this array is immutable. //also making it immutable will make all the elements //immutable. return assumeUnique(array); }
Nov 11 2013
On Tuesday, 12 November 2013 at 01:33:29 UTC, TheFlyingFiddle wrote:On Tuesday, 12 November 2013 at 01:15:02 UTC, Louis Berube wrote:Plz ignore my pervious statment. I guess i'm to tiered atm i take it all back.I thought the parantheses in the array declaration would do the trick, but apparently not.Well when you create an immutable array you cannot change any of the elements in the array. I'm guessing what you want is a mutable array that contains immutable objects. I don't think you can create such an array in D (i am not sure though i doubt that it would be usefull anyhow)
Nov 11 2013
On Tuesday, 12 November 2013 at 01:36:12 UTC, TheFlyingFiddle wrote:Plz ignore my pervious statment. I guess i'm to tiered atm i take it all back.I rly am to tiered to think straight. Ingore the ignore post. I am sorry for being confusing. auto a = new immutable(Test)[]; //The array is immutable and you cannot change the elements in any way. //However the array can stil be rebound like so a = new immutable(Test)[]; or like this a ~= new immutable Test(3); auto a new immutable Test[]; //The array is immutable and you cannot change the elements in any way. b = new immutable Test[]; //This will fail. //and so will this. b ~= new immutable Test(3); I don't think you can create rebindable immutable objects that are not wrapped by something. (like an array or the solution i present bellow) Alternative solution: Test is a rebindable immutable object (it's immutable in the same sense that strings are immutable) class Test { private immutable uint value; this(uint value) { this.value = value; } } unittest { auto test = new Test(5); //The array is mutable but objects of type Test are immutable. auto array = new Test[5]; array[0] = test; }
Nov 11 2013
On Tuesday, 12 November 2013 at 01:15:02 UTC, Louis Berube wrote:Thanks, I think I understand. Now, how about an array of immutables: immutable class Test { public: this(in uint value) { this.value = value; } unittest { auto t = new immutable Test(4); assert (t.value == 4); } unittest { auto tarray = new immutable(Test)[3]; tarray[0] = new immutable Test(4); // "Error: cannot modify // immutable expression // tarray[0]" } private: uint value; } I thought the parantheses in the array declaration would do the trick, but apparently not.Once you initialize an immutable class reference, you won't be able to rebind it anymore. As far as I know there's two straight methods. immutable class Test { this(in uint value) { this.value = value; } uint value; } void main() { version(Try1) { // 1. concatenate elements immutable(Test)[] tarray; tarray ~= new immutable Test(2); tarray = new immutable Test(1) ~ tarray; } else { // 2. use array literal syntax auto tarray = [ new immutable Test(1), new immutable Test(2), ]; } static assert(is(typeof(tarray[0]) == immutable(Test))); assert(tarray.length == 2) assert(tarray[0].value == 1); assert(tarray[1].value == 2); } In D, you can reserve continuous memory area for array appending by using built-in 'reserve' method. Therefore in most cases, "reserve elements on empty array, then append created elements" would be the efficient way to initialize the array of immutable elements. void main() { immutable(Test)[] tarray; tarray.reserve(2); auto save_ptr = tarray.ptr; assert(save_ptr !is null && tarray.capacity >= 2); // underlying memory is allocated and the appendable number is more than 2. assert(tarray.length == 0); // but array itself is still empty. tarray ~= new immutable Test(1); tarray ~= new immutable Test(2); assert(tarray.length == 2); // array is expectedly filled. assert(tarray.ptr is save_ptr); // But the two concatenations didn't reallocate underlying memory. } And I don't recommend to use std.exception.assumeUnique, because it is just a cosmetic function to make ugly (but necessary for some reason) array cast grep-able and human-readable. Kenji Hara
Nov 12 2013
Thanks to both TFF and Kenji for their excellent explanations. I think my head is going to explode ;). So, as I understand it, there are two sorts of immutable entities in D. The first is probably the one most familiar to the majority of us, which is an entity with immutable contents but with mutable binding. This is what TFF illustrated so well in his post above and what we are all familiar with as "string". The second will take me longer to get used to, which is an entity with immutable contents *and* with immutable binding. This is what I tripped over in my example and what Kenji adroitly showed how to deal with in his post. Does this correctly sum up what I have read? If so, this conversation has cleared up a great deal of my misunderstanding of how "immutable" works. It would be great to see the above examples in a D reference or tutorial (maybe the second edition of Andrei's book?). Many thanks.
Nov 12 2013
On Wednesday, 13 November 2013 at 01:40:27 UTC, Louis Berube wrote:Does this correctly sum up what I have read? If so, this conversation has cleared up a great deal of my misunderstanding of how "immutable" works. It would be great to see the above examples in a D reference or tutorial (maybe the second edition of Andrei's book?).Both yes and now. You are correct that those are two observable semantics but in practice it is the same immutability. I think it becomes easier to get when based on C foundation: const char * s; // mutable pointer to constant elements" char * const s; // constant pointer to mutable elements" const char * const; // constant pointer to constant elements In C "const" qualifier applies only to part of type it is qualified with. In D, however, both "const" and "immutable" are transitive. That means that they do apply to type it is qualified with AND all stuff accessible from it. Without explicit brackets those apply to whole type: immutable char * s; // immutable pointer, immutable elements immutable(char*) s; // equivalent to (1) immutable(char) * s; // mutable pointer, immutable elements There is no such concept in D type system as "immutable pointer to mutable elements". So your two cases both use same "immutable", it is just applied to different parts of type. It is all actually mentioned in TDPL as far as I can remember, but maybe relies too much on existing familiarity with transitivity concept.
Nov 13 2013
On Wednesday, 13 November 2013 at 01:40:27 UTC, Louis Berube wrote:Thanks to both TFF and Kenji for their excellent explanations. I think my head is going to explode ;). So, as I understand it, there are two sorts of immutable entities in D. The first is probably the one most familiar to the majority of us, which is an entity with immutable contents but with mutable binding. This is what TFF illustrated so well in his post above and what we are all familiar with as "string". The second will take me longer to get used to, which is an entity with immutable contents *and* with immutable binding. This is what I tripped over in my example and what Kenji adroitly showed how to deal with in his post. Does this correctly sum up what I have read? If so, this conversation has cleared up a great deal of my misunderstanding of how "immutable" works. It would be great to see the above examples in a D reference or tutorial (maybe the second edition of Andrei's book?). Many thanks.There's a Rebindable template in Phobos which I think does what you want:
Nov 13 2013
On Tuesday, 12 November 2013 at 00:43:34 UTC, Louis Berube wrote:Edit for (hopefully) better readability: Simple example: // file immutable_example.d immutable class Test { public: this(in uint value) { this.value = value; } unittest { auto t = new Test(4); // "Error: immutable method // immutable_example.Test.this // is not callable using // a mutable object" assert (t.value == 4); } private: uint value; }Assuming this is not a compiler issue, what am I missing? Integer literal is about as immutable as it gets.Well the issue is that new Test(5) is not an immutable object. To create an immutable object use new immutable Test(5). class Test { private uint value; //Ctor needs to be immutable to create immutable objects. this(uint value) immutable { this.value = value; } } unittest { //use the immutable keyword. auto a = new immutable Test(5); //or auto b = new immutable(Test)(6); //Will not work //auto c = new Test(7); //new Test not an immutable object. }
Nov 11 2013