Michel Fortin wrote:
On 2010-06-26 08:12:24 -0400, Justin Johansson <[email protected]> said:
Simen kjaeraas wrote:
Justin Johansson <[email protected]> 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.