mutable, const, immutable guidelines

Daniel Davidson nospam at spam.com
Thu Oct 17 06:34:52 PDT 2013


On Wednesday, 16 October 2013 at 20:33:23 UTC, H. S. Teoh wrote:
> On Wed, Oct 16, 2013 at 09:45:09PM +0200, Daniel Davidson wrote:
>> On Wednesday, 16 October 2013 at 19:12:48 UTC, Dicebot wrote:
> [...]
>> >I think any usage of immutable with types/entities not 
>> >initially
>> >designed for immutability is an potential mistake and in that
>> >sense it is good that change has broken the user code. Same 
>> >goes
>> >for operating on immutable entity in generic code as if it is 
>> >a
>> >value type without actually checking it via introspection.
>> 
>> I don't disagree. Now, what does it mean to "initially design 
>> for
>> immutability" and what are the guidelines. I thought that was 
>> kind
>> of what we were talking about here. How to effectively use 
>> const and
>> immutable.
>

Thanks - this is most helpful.

> I'd say that user code should use const, not immutable (unless 
> the
> library provides a way of constructing immutable instances of 
> the type,
> of course), because immutable makes assumptions about 
> implementation
> details, which should not be known unless you break 
> encapsulation. As a
> user of a properly encapsulated type, I can't make any 
> guarantees about
> its immutability; the best I can do is to promise I don't 
> change it
> myself -- i.e., const.
>

The distinction between user code and the rest (non-user code?) 
is not enough for me to get clear guidance. I am writing user 
code, the vast majority will be in libraries because I find that 
helpful. I would hate to have a separate set of rules for my code 
and the code I use. We should strive for guidelines that work in 
general - as in this is a good way to do D.

But leaving "user code" aside, I like the argument and the vote 
for const over immutable.


> Immutable should be used in library code to provide strong 
> guarantees to
> the user: since you're the one responsible for implementing the 
> type,
> you're in the position to make guarantees about its uniqueness 
> (and
> hence, immutability).
>

I don't see the benefit of separating usage of types, usually via 
functions where mutability guarantees adorn the types, and 
implementation guarantees in a world with turtles all the way 
down. Maybe if those guarantees are totally hidden from user code 
via encapsulation then the impact of immutable and the 
difficulties of dealing with it are lessened. But then is the 
immutable guarantee for the user or just the developer of the 
encapsulated non-user code?

How about this... here is a plea for ideas on a good use of 
immutable for a type with potentially mutable aliasing. String I 
think is a great use of immutable but char will likely never have 
aliasing introduced to it. At this stage I want the information 
for educational purposes, because based on this thread and my 
experimentation - Ali's presentation guidelines aside - I am 
about to abandon immutable altogether. The fight is too hard and 
my skills too weakened.

>
> [...]
>> One general idea that was presented by Ali is that an immutable
>> parameter means that not only are you guaranteeing that you 
>> will not
>> change your data, but also that no one else, even in another 
>> thread
>> will. That sounds appealing. After all, who doesn't want the 
>> data
>> they are using in a function to not change from underneath 
>> them?
>
> I'm actually wary of this view, to be honest. An immutable 
> parameter
> means you expect your *caller* to provide you with a value that 
> cannot
> be changed, not by you, nor by anybody else, ever. Sure, it's 
> nice to
> have, but that imposes a rather high bar on your callers. They 
> have to
> be responsible to guarantee that whatever they hand to you 
> cannot be
> changed by anything or anyone else, at any time. If they can do 
> this,
> then great; if not, they won't be able to call your function.
>

I now agree with you on this, especially since it goes with my 
new guideline of don't use immutable.

>
>> Suppose you have highly structured, deeply nested reference 
>> data you
>> read from a nosql DB. Surely there is opportunity and some 
>> benefit
>> to use immutable? The result of the query is just a read only 
>> data
>> source. But then that data will be consumed - presumably by
>> functions with either immutable or const parameters. If all
>> signatures use const then when can you benefit from the fact 
>> that
>> the data is really immutable (by the time it gets to a 
>> function with
>> const parm the fact that it really was/is immutable is lost.
>
> I'm of the view that code should only require the minimum of 
> assumptions
> it needs to actually work. If your code can work with mutable 
> types,
> then let it take a mutable (unqualified) type. If your code 
> works
> without modifying input data, then let it take const. Only if 
> your code
> absolutely will not work correctly unless the data is 
> guaranteed to
> never change, ever, by anyone, should it take immutable.
>

I don't have the instincts yet to really buy this. Perhaps a 
specific example would be helpful.

I think most of the time `foo(ref const(T) t)` is written such 
that it is assumed t is never changed during the span of foo and 
the compiler helps. While it is possible to, in a single thread 
call out to code that also has a handle to shared state so t 
could be accidentally or purposely modified elsewhere, it is 
probably a rare design goal.

Take the query example. A big mongo db query result comes back 
and is deserialized into a large web of json like data - lists, 
dictionaries at many levels. Is that a good reason then for 
`foo(ref immutable(QueryResult) qr)`. Surely while you are 
working on query result you don't want it to change. I am 
ambivalent here because immutable sounds appealing. Any iteration 
over a hash in the data set must be immutable. I think this is 
the expectation most have with all const or immutable types taken 
in a function. Sticking with const just makes life easier.


> I'm not sure what "benefits" you get from requiring immutable 
> when the
> code doesn't really need to depend on immutability. It just 
> makes the
> code harder to use (you have to make sure whatever you pass to 
> it is
> immutable, and sometimes that's not easy to guarantee, and 
> would require
> a lot of copying). Immutable only benefits you when the code 
> *can't*
> work correctly unless the data is guaranteed never to change, 
> ever. Hash
> table keys come to mind -- if you compute the hash value of the 
> key and
> use that to determine which slot to put the data into, it would 
> be very
> bad if somebody else mutated that key via a mutable reference 
> after the
> fact -- now your AA is broken because the hash value no longer 
> matches
> the key.  By requiring an immutable key, you ensure that this 
> never
> happens.
>

I like the AA example - since it sounds like a good use for 
immutable.

> Note that in D, everything is thread-local by default unless 
> explicitly
> made shared, so using immutable to guarantee other threads 
> won't mutate
> the data isn't really necessary.
>
>
> T


More information about the Digitalmars-d-learn mailing list