On Tue, Aug 28, 2018 at 08:18:57AM +0000, Eugene Wissner via Digitalmars-d wrote: [...] > There are still valid use cases where const should be "broken". One of > them is mutex (another one caching). I have very little experiance in > multi-threaded programming, but what do you think about "mutable" > members, despite the object is const?
The problem with compromising const is that it would invalidate any guarantees const may have provided. Const in D is not the same as const in languages like C++; const in D means *physical* const, as in, the data might reside in ROM where it's physically impossible to modify. Allowing the user to bypass this means UB if the data exists in ROM. Plus, the whole point of const in D is that it is machine-verifiable, i.e., the compiler checks that the code does not break const in any way and therefore you are guaranteed (barring compiler bugs) that the data does not change. If const were not machine-verifiable, it would be nothing more than programming by convention, since it would guarantee nothing. Allowing const to be "broken" somewhere would mean it's no longer machine-verifiable (you need a human to verify whether the semantics are still correct). Many of D's const woes can actually be solved if we had a language-supported way of declaring the equivalence between const(U!T) and U!(const(T)), AKA head-mutable. The language already supports a (very) limited set of such conversions, e.g., const(T*) is assignable to const(T)*, because you're just making a copy of the pointer, but the target is still unchangeable. However, because there is no way to specify such a conversion in a user-defined type, that means things like RefCounted, or caches, or mutexes, cannot be made to work without either ugly workarounds or treading into UB territory by casting away const. But if there is a way for a user-defined template U to define a conversion from const(U!T) to U!(const(T)) (the conversion code, of course, would have to be const-correct and verifiable by the compiler), then we could make it so that U!(const(T)) contained a mutable portion (e.g., the refcount, mutex, cache, etc.) and an immutable portion (the reference to the const object). T -- In order to understand recursion you must first understand recursion.