== Quote from Marco Leise (marco.le...@gmx.de)'s article > Am 02.08.2011, 01:51 Uhr, schrieb Walter Bright > <newshou...@digitalmars.com>: > > I've talked to many people who use logical const extensively in C++, and > > really want it. If you dig down into what's happening, you'll find that > > logical const isn't actually supported by C++. It's a convention. > > There's simply nothing in the language that enforces that convention. > > > > The reason "logical const" does not work with const in D is because D > > actually enforces const semantics, and relies on that enforcement. > > > > Since logical const is a convention in C++ anyway, you can have logical > > const in D, too. Just put in a comment: > > > > struct S /* This struct is logical const */ > > { ... } > > > > and then follow the convention just as you would with C++. > > > > Const in C++ is not powerful - it's simply a fraud - and the two get > > confused. > I can understand the point of view of the compiler developer and I don't > question that D const has advantages. It is definitly good to have > transitive const in some use cases. Until today I didn't even know about > logical const. But the more I think about it and its applications it looks > like a valuable feature. > I'm a typical OOP programmer and I generally avoid pointers where possible > and use encapsulation - that is - mark methods and data fields private. > But there are these strong cases where you cannot afford to have the usual > transitive const. Instead you really want a high-level logical const. One > that makes no sense to the compiler and is a 'fraud'. That is in OOP you > give away a const reference to some object, meaning that the outside world > cannot modify it logically. The encapsulated inner state though should not > be affected by this. > The example with the Matrix class is an excellent example. Here the > programmer wants to make sure that the owner of the Matrix can safely give > away that Matrix object without having to worry that the logical state > changes, i.e. the mathematical representation changes. This is the > 'caching' use case. > Another one I've found is object composition: > http://en.wikipedia.org/wiki/Object_composition#UML_notation > The motor in your car: If the car is a const reference the motor has to be > protected by that as well (composition). > But if I call car.getVendor() I expect the mutable instance of the vendor > object to call car.getVendor().buy(car.getModel(), 10) for my company's > car pool. > On this higher level C++ gives the form of logical protection for the > 'caching' case that I need as an OO programmer. > - Marco
The problem as I see it is that D has two separate concepts that are conflated: const and immutable. In fact, I'd argue that immutable shouldn't even exist in its current standalone state but should rather be part of an ownership system a-la Bartosz' suggested annotation system. In the context of single threaded programs const mustn't be transitive. E.g. class Foo { int a; ... } class Bar { Foo foo; ...} void func(const Bar b); void gunc(immutable Bar b); func should be able to change b.foo.a but not b.foo (foo is head-const or "final") gunc however will enforce transitivity and will not allow to change b.foo.a In the context of multi-threaded programs, casting const(T) to an immutable(T) would require locking/synchronization in order to preserve correctness. To conclude, Instead of D's current model where both T and immutable(T) can be "up-casted" to const(T) I'm suggesting T -> const(T) -(locked)-> immutable(T) In addition, compile-time "manifest" consts via enum should be removed in favor of immutable.