www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Simple immutable example doesn't work - why???

reply "Louis Berube" <louis.p.berube gmail.com> writes:
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
parent reply "Louis Berube" <louis.p.berube gmail.com> writes:
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
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
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
parent reply "Louis Berube" <louis.p.berube gmail.com> writes:
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
next sibling parent reply "TheFlyingFiddle" <theflyingfiddle gmail.com> writes:
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
parent reply "TheFlyingFiddle" <theflyingfiddle gmail.com> writes:
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:
 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)
Plz ignore my pervious statment. I guess i'm to tiered atm i take it all back.
Nov 11 2013
parent "TheFlyingFiddle" <theflyingfiddle gmail.com> writes:
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
prev sibling parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
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
parent reply "Louis Berube" <louis.p.berube gmail.com> writes:
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
next sibling parent "Dicebot" <public dicebot.lv> writes:
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
prev sibling parent "Rene Zwanenburg" <renezwanenburg gmail.com> writes:
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
prev sibling parent "TheFlyingFiddle" <theflyingfiddle gmail.com> writes:
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