On Thursday, 18 February 2016 at 22:40:32 UTC, Walter Bright wrote:
On 2/18/2016 4:16 AM, Jonathan M Davis wrote:
headconst may solve the extern(C++) problem, but it really doesn't solve the
problems we have with const.

'mutable' doesn't really solve a problem, it just means that C++ 'const' is a documentation aid, not a guarantee.

It's still a guarantee for those members that aren't mutable. It's allowing casting away const and mutating that totally blows the guarantees out of the water. You can actually look at the type to see which members are mutable and know what might change, and usually it's stuff like mutexes that are perfectly okay to change, whereas with casting, you'd have to look at every spec of code that uses the object to see what it does if you want to be sure that a const object or particular member isn't mutated.

And while I very much like the fact that D doesn't consider casting away const and mutating to be defined behavior and that it has stronger guarantees than C++, the reality of the matter is that in many cases, it ultimately provides far worse guarantees than C++. While C++'s const does have too many backdoors, at least when you use it, it catches accidental mutation (e.g. getting the arguments reversed when calling copy from the algorithm header will result in an error). But if you're forced to drop const entirely as tends to happen in D, then you don't get that. So, for some code, the stricter const in D is great, but for a lot of it, it makes things worse. In spite of the stronger guarantees, you ultimately end up with less protection. And since the compiler actually lets you cast away const and mutate in D to your heart's content without complaining at all (even if it's technically undefined behavior), there are plenty of folks that do it, because D doesn't provide mutable, and they assume that because you can cast away const, mutating it must be fine, just like with C++. So, while in principle, D's const provides better guarantees, in practice, it really doesn't. Casting away const would have to be illegal for it really provide those guarantees. And because it's so restrictive, it frequently gets avoided anyway. So, even if it doesn't get circumvented, it still fails to provide good guarantees, because it's not used.

At least if we added @mutable, we'd be providing a controlled means of escaping const in the cases where it's needed, avoiding issues with immutable like you'd potentially get if you cast away const and mutated. And any code which didn't use @mutable would be able to rely on the full guarantees that we have now (the only problem being folks that cast away const and mutated, thinking that it was okay, but they'd have less incentive to if they had @mutable).

In principle, I agree that having something like @mutable does weaken const, but in practice, it does a much better job of catching bugs, because then you're actually able to use const with more complicated objects. And unlike casting away const, @mutable is easily detected and accounted for.

D's const simply doesn't work once you start doing stuff like putting allocators or reference counts into the mix. And while maybe we could not care about that when we thought that it was fine to use the GC with everything, I think that we have a much harder time holding that position now. As principled as D's current position on const may be, it's highly impractical.

- Jonathan M Davis

Reply via email to