mutable, const, immutable guidelines
Daniel Davidson
nospam at spam.com
Wed Oct 16 11:49:51 PDT 2013
On Wednesday, 16 October 2013 at 17:55:14 UTC, H. S. Teoh wrote:
> 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.
>
I think the term "mutable aliasing" and "what you want" don't
work together. "mutable aliasing" is not about context of usage
or what you want, it is a compile time attribute of a struct. I
want to use associative arrays in composition because I think
they are the way I view and use my data. `struct T {
string[string] i; }` has mutable aliasing, like it or not. So, it
is not so much that I want mutable aliasing - in fact I fear it.
But once you use AAs it is a fact of life.
>
>> 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.
>
yes - it requires transitive deep copy.
> 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.
>
I agree that string behaves as you say. I don't quite agree that
immutable alone is the reason it does. I think it is an byproduct
of the way immutable(T)[] is implemented. It is an implementation
detail and relying on that could lead to bad deduction. We
covered that here in this thread:
http://forum.dlang.org/post/jfjudswamyxlttgsdwva@forum.dlang.org
> 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
Agreed with the description of the behavior. But disagree on why.
It works that way because T[] is modeled as contiguous memory and
the api associated with slice of type immutable(T)[] means there
is no unsafe sharing. So, `struct T { string[string] i; }` and
`struct T { immutable(S)[string] }` do not have the same
properties because they have a different layout model.
Is the suggestion here: use immutable in any composition context
where you have slices and you want to not "worry about mutable
aliasing". So, do like string does: any case where you have T[]
as a member, prefer immutable(T)[] since then you don't have to
worry about sharing. Well, not sure that works in general because
the T in string is char and has no mutable aliasing itself.
Suppose T itself has mutable aliasing, then what? Or, suppose it
is a struct with no mutable aliasing *now*. Who's to say it won't
change.
So, where does all this leave us w.r.t. a good set of guidelines?
More information about the Digitalmars-d-learn
mailing list