On Tue, Jun 21, 2016 at 02:24:03AM +0000, jmh530 via Digitalmars-d-learn wrote: > I feel like I have a reasonable understanding of when to use const as > a parameter in a function or for const member functions. However, I > don't really understand why/when it should be used as a type modifier. > > For instance, the Programming in D book basically just says > (http://ddili.org/ders/d.en/const_and_immutable.html) that a const > variable is the same as an immutable variable, but you should just use > immutable.
I think that's an oversimplification. :-) Here's a diagram that helped me understand what the deal with const/immutable is: const / \ (mutable) immutable This is a kind of "type inheritance diagram" analogous to a class inheritance diagram. What it means is that mutable and immutable cannot implicitly convert to each other (except for atomic by-value types), but both mutable and immutable can implicitly convert to const. Why? Because const means "you are not allowed to modify this value" (but somebody else may). Converting mutable to const, which usually happens in function calls, simply means the callee is bound to a contract never to modify the value, but the caller may have a mutable reference to the same value and may legally modify it. OTOH, immutable means "NOBODY is allowed to modify this value". Meaning that the value is truly, physically immutable; neither caller nor callee nor any 3rd party may modify its value. This is actually a strong guarantee because the compiler can statically verify that nobody actually modifies the value; therefore certain optimizations can be made (e.g., storing it in ROM, in an immutable data segment, eliding multiple reads from the variable because it is guaranteed that its value never changes no matter what else happens in between). Such optimizations cannot be applied to const, because we aren't guaranteed that a 3rd party won't change the value after we last read it. Const only means *we* cannot change it. So const is a weaker form of immutable... its main purpose is to reduce redundancy in functions that can work with both mutable and immutable data. For example, a function that only reads the value of a parameter can be passed an immutable value safely -- since it won't modify it -- and can also take a mutable value -- even though modification is valid, the function doesn't modify it anyway. This means we can pass both a mutable value and an immutable value to the same function and it's fine, as long as the function itself never changes anything. But we can't write the function as: auto func(immutable X x) { ... } because converting mutable to immutable is illegal, so we couldn't call the function with mutable arguments. Obviously we also can't write the function without type qualifiers: auto func(X x) { ... } because immutable cannot convert to mutable, so we can't pass an immutable value to it. The solution is to use const: auto func(const(X) x) { ... } Const ensures that func doesn't attempt to modify an immutable value when we give it one, but since const doesn't guarantee a 3rd party won't modify the value, we can also legally pass a mutable value to it. Since func is bound by const never to modify x, it doesn't matter. Without const, we'd have to write two identical functions, one that takes an immutable value, and one that takes a mutable value. Const lets us unify the two, which is valid since const ensures that func doesn't do any funny business behind our backs by trying to modify its arguments. Of course, this is only part of the story. The other part is that if a value has a by-value type, then it's OK to implicitly convert to/from immutable: because you're always making a copy of the by-value type. You can't convert a mutable *reference* to an immutable reference or vice versa (otherwise you could use the mutable reference to break immutability), but you *can* copy the value itself from mutable to immutable and vice versa. So a function that takes an int argument can be legally passed an immutable int -- since the function gets a copy of the immutable value, and it's OK to modify the copy instead of the original value. With this in view, it would make sense that const would usually be used in function parameters, since that is where it's most useful, whereas immutable would normally be used in variables that you wish to initialize once and have its value never change again thereafter. This is probably where that advice came from that you should use immutable variables rather than const variables. Still, there *are* times when const variables make sense -- this applies when iterating read-only over a collection of objects, for example. The iterator would need to be const so that it can refer to both mutable and immutable members of the collection, again so that you don't have to copy-n-paste the same code, one in a function that takes an immutable collection and another that takes a mutable collection. Hope this helps. T -- Talk is cheap. Whining is actually free. -- Lars Wirzenius