mutable, const, immutable guidelines

H. S. Teoh hsteoh at quickfur.ath.cx
Wed Oct 16 10:53:54 PDT 2013


On Wed, Oct 16, 2013 at 07:23:24PM +0200, Daniel Davidson wrote:
> On Wednesday, 2 October 2013 at 13:09:34 UTC, Daniel Davidson wrote:
[...]
> >Maybe it is a philosophical question, but where does immutability
> >really come from? Is it an aspect of some piece of data or is it a
> >promise that function will not change it? Or is it a requirement
> >by a function that data passed not be changed by anyone else?

I think it helps to realize that D's const system is different from
C++'s.

Immutable means the data will never change, ever. It means you can put
that data in read-only memory, maybe burned into a ROM chip or something
like that.

Const means *you* can't change the data, but somebody else may be able
to.

Therefore:


[...]
> After trying for several days to use immutable with types containing
> some mutable aliasing I have come to the conclusion that maybe rule
> number one should be:

If you have mutable aliasing, that means the data cannot be immutable.
Use const.


> If you have a type that has now or may ever have in the future any
> mutable aliasing (e.g. inclusion of T[] or T1[T1] where Ts are
> mutable) do not ever use the immutable keyword in any context as
> things just break down.

Yes, because immutable means nothing, no one, can change the data after
it's constructed, ever. If you want mutable aliasing, what you want is
const, not immutable.


> If you have had more success with a immutable with types containing
> mutable aliasing and can share your success story that would be
> great.
[...]

Maybe it's helpful to understand how D's const system works. The
following diagram may help (please excuse the ASCII graphics):

	       const
	      /     \
	mutable     immutable

What this means is that const subsumes mutable and immutable. A mutable
type can be implicitly converted to a const type (the receiver of the
const can't modify the data, which is fine since the code holding the
mutable reference can still mutate it), and so can immutable (immutable
cannot be modified, ever, and const doesn't let you modify it either, so
it's OK to make a const reference to immutable data). However, you
cannot implicitly convert between mutable and immutable, unless you're
copying the data by value.

So if you have immutable data and want to make changes, you have to
first make a copy of the data, then mutate it at will.

What's the use of immutable, you ask? Immutable makes hard guarantees
about the non-changeability of some piece of data. This makes it useful
for implementing strings -- in fact, the 'string' type in D is just an
alias for immutable(char)[]. You can take substrings (slices) of any
given string freely, and be assured that your copy of the (sub)string
will never unexpectedly change its value from somewhere else in the
code. This saves the need for a lot of copying, which can be costly.

One interesting subtlety here is that 'string' is immutable(char)[], but
not immutable(char[]). The latter would mean that the string itself can
never be changed -- you couldn't assign to it, you couldn't append to
it, etc., which would make strings a lot less useful than they are. But
by making strings a *mutable* array of *immutable* chars, you allow the
string to be appended to, substring'd, etc., all while guaranteeing that
the underlying bytes themselves will never change. So you can have the
best of both worlds: you can append to strings, take substrings, assign
strings to each other, etc., yet at the same time be assured that the
list of intermediate substrings you stored somewhere during the process
will continue to retain the values you assigned to them, because the
underlying bytes they point to are immutable, and therefore guaranteed
never to change.


T

-- 
Just because you survived after you did it, doesn't mean it wasn't stupid!


More information about the Digitalmars-d-learn mailing list