www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What's the authoritative difference between immutable and const for

reply Justin Johansson <no spam.com> writes:
While my googling on "immutable" and "const" search words using 
site:digitalmars.com has not thrown up authoritative/definitive answers, 
  please accept my apologies for (re)asking this question that I feel 
sure has been asked numerous time before on this ng.

Specifically, I wish to have class which has a member variable which 
cannot be changed (and is guaranteed not to change) and this member 
variable happens to be a reference type (i.e. it's a pointer in C++ 
parlance) and, further more, the instance of the class which that 
variable refers to is to be deep immutable.

For instance, with

class Foo
{
}

class Bar
{
	Foo foo;
}

consider instances of Foo to be in ROM and instances of Bar to be in RAM 
  and once a Bar instance is constructed, the member variable foo itself 
is not allowed to be modified.

Thanks for answers,

Justin Johansson
Jun 26 2010
next sibling parent Justin Johansson <no spam.com> writes:
btw.  I have read the D2 help page re Const and Immutable but don't find 
the doco sufficiently rigorous with respect to reference types that one 
could unambiguously interpret the semantics of the same or implement 
said semantics in a D compiler.
Jun 26 2010
prev sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Justin Johansson <no spam.com> wrote:

 Specifically, I wish to have class which has a member variable which  
 cannot be changed (and is guaranteed not to change) and this member  
 variable happens to be a reference type (i.e. it's a pointer in C++  
 parlance) and, further more, the instance of the class which that  
 variable refers to is to be deep immutable.

 For instance, with

 class Foo
 {
 }

 class Bar
 {
 	Foo foo;
 }

 consider instances of Foo to be in ROM and instances of Bar to be in RAM  
   and once a Bar instance is constructed, the member variable foo itself  
 is not allowed to be modified.

What you want is class Bar { immutable Foo foo; } Now, I believe there are some problems constructing immutable objects, for which the assumeUnique template in std.contracts is created. -- Simen
Jun 26 2010
parent reply Justin Johansson <no spam.com> writes:
Simen kjaeraas wrote:
 Justin Johansson <no spam.com> wrote:
 
 Specifically, I wish to have class which has a member variable which 
 cannot be changed (and is guaranteed not to change) and this member 
 variable happens to be a reference type (i.e. it's a pointer in C++ 
 parlance) and, further more, the instance of the class which that 
 variable refers to is to be deep immutable.

 For instance, with

 class Foo
 {
 }

 class Bar
 {
     Foo foo;
 }

 consider instances of Foo to be in ROM and instances of Bar to be in 
 RAM   and once a Bar instance is constructed, the member variable foo 
 itself is not allowed to be modified.

What you want is class Bar { immutable Foo foo; } Now, I believe there are some problems constructing immutable objects, for which the assumeUnique template in std.contracts is created.

Thanks for that Simen. Thinking about this a bit more, there are four possibilities as indicated in the following table :- Variable foo is modifiable | Data referred to by foo is modifiable ---------------------------+-------------------------------------- No | No No | Yes Yes | No Yes | Yes ---------------------------+-------------------------------------- What combination of immutable and const storage classes make for the implementation of these four possibilities?
Jun 26 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-06-26 08:12:24 -0400, Justin Johansson <no spam.com> said:

 Simen kjaeraas wrote:
 Justin Johansson <no spam.com> wrote:
 
 Specifically, I wish to have class which has a member variable which 
 cannot be changed (and is guaranteed not to change) and this member 
 variable happens to be a reference type (i.e. it's a pointer in C++ 
 parlance) and, further more, the instance of the class which that 
 variable refers to is to be deep immutable.
 
 For instance, with
 
 class Foo
 {
 }
 
 class Bar
 {
     Foo foo;
 }
 
 consider instances of Foo to be in ROM and instances of Bar to be in 
 RAM   and once a Bar instance is constructed, the member variable foo 
 itself is not allowed to be modified.

What you want is class Bar { immutable Foo foo; } Now, I believe there are some problems constructing immutable objects, for which the assumeUnique template in std.contracts is created.

Thanks for that Simen. Thinking about this a bit more, there are four possibilities as indicated in the following table :- Variable foo is modifiable | Data referred to by foo is modifiable ---------------------------+-------------------------------------- No | No No | Yes Yes | No Yes | Yes ---------------------------+-------------------------------------- What combination of immutable and const storage classes make for the implementation of these four possibilities?

I think your table isn't very practical because it eludes the question of "modifiable by whom?". If you have a const(int)*, the integer it points to cannot be modified *through this pointer*, but you could have another a non-const pointer lying elsewhere through which you can change the integer. If you had a immutable(int)*, then you know that no where in the program lies a non-const reference to it and as such you know the value of the integer will never change. So const means you can't modify it; immutable means nobody can modify it and the value is guarantied to stay constant. As for your table, the answer is this: 1. const(int*) foo; or immutable(int*) foo; 2. // impossible in D, constness is transitive propagates to referenced data 3. const(int)* foo; or immutable(int)* foo; 4. int* foo; Notice that both const and immutable can be used interchangeably to fill your table as it depends on something you left unspecified: whether the data is unmodifiable through this pointer only or truly unmodifiable from everywhere in the program. That's the essence of the difference between const and immutable. Now, when it comes to classes and objects you have the problem that they're implicitly references and because of this you can't use a different constness for the object and the reference to it. That's a syntactic problem because there are no '*' marker to include or exclude. The only solution for now is to use a struct that casts its way around the problem. See Rebindable in std.typecons (but in my experience it doesn't work very well). -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 26 2010
parent Justin Johansson <no spam.com> writes:
Michel Fortin wrote:
 On 2010-06-26 08:12:24 -0400, Justin Johansson <no spam.com> said:
 
 Simen kjaeraas wrote:
 Justin Johansson <no spam.com> wrote:

 Specifically, I wish to have class which has a member variable which 
 cannot be changed (and is guaranteed not to change) and this member 
 variable happens to be a reference type (i.e. it's a pointer in C++ 
 parlance) and, further more, the instance of the class which that 
 variable refers to is to be deep immutable.

 For instance, with

 class Foo
 {
 }

 class Bar
 {
     Foo foo;
 }

 consider instances of Foo to be in ROM and instances of Bar to be in 
 RAM   and once a Bar instance is constructed, the member variable 
 foo itself is not allowed to be modified.

What you want is class Bar { immutable Foo foo; } Now, I believe there are some problems constructing immutable objects, for which the assumeUnique template in std.contracts is created.

Thanks for that Simen. Thinking about this a bit more, there are four possibilities as indicated in the following table :- Variable foo is modifiable | Data referred to by foo is modifiable ---------------------------+-------------------------------------- No | No No | Yes Yes | No Yes | Yes ---------------------------+-------------------------------------- What combination of immutable and const storage classes make for the implementation of these four possibilities?

I think your table isn't very practical because it eludes the question of "modifiable by whom?". If you have a const(int)*, the integer it points to cannot be modified *through this pointer*, but you could have another a non-const pointer lying elsewhere through which you can change the integer. If you had a immutable(int)*, then you know that no where in the program lies a non-const reference to it and as such you know the value of the integer will never change. So const means you can't modify it; immutable means nobody can modify it and the value is guarantied to stay constant. As for your table, the answer is this: 1. const(int*) foo; or immutable(int*) foo; 2. // impossible in D, constness is transitive propagates to referenced data 3. const(int)* foo; or immutable(int)* foo; 4. int* foo; Notice that both const and immutable can be used interchangeably to fill your table as it depends on something you left unspecified: whether the data is unmodifiable through this pointer only or truly unmodifiable from everywhere in the program. That's the essence of the difference between const and immutable. Now, when it comes to classes and objects you have the problem that they're implicitly references and because of this you can't use a different constness for the object and the reference to it. That's a syntactic problem because there are no '*' marker to include or exclude. The only solution for now is to use a struct that casts its way around the problem. See Rebindable in std.typecons (but in my experience it doesn't work very well).

Thanks for the detailed explanation, especially that you have addressed all 4 possibilities (even though, as you say, the table might be impractical) and also identified the syntactic problem when it comes to classes and objects.
Jun 26 2010