What's the authoritative difference between immutable and const for reference types?

Justin Johansson no at spam.com
Sat Jun 26 12:05:39 PDT 2010


Michel Fortin wrote:
> On 2010-06-26 08:12:24 -0400, Justin Johansson <no at spam.com> said:
> 
>> Simen kjaeraas wrote:
>>> Justin Johansson <no at 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.


More information about the Digitalmars-d mailing list