const(FAQ)

guslay guslay at gmail.com
Sat Mar 29 10:58:41 PDT 2008


Kevin Bealer Wrote:

> guslay Wrote:
> 
> 
> The times that I can remember using logical const in C++ have usually been for "compatibility" reasons, i.e. there is an interface and the method is defined something like "int foo(...) const = 0;", or backward compatibility such as when "lazy" evaluation is added to a class.  Was const a  need or a premature optimization?  When is there a case where logical const actually provides benefits over leaving the methods non-const?
> 
> I would suggest that in many cases, D interfaces should avoid const since you can't know if lazy evaluation and similar are needed.  Using const here is a case of overspecifying, like an interface that takes a reference to a "StudentCheckingAccount" object but only uses methods from the parent interface "CheckingAccount" or grandparent "Account" object (assume an inheritance hierarchy following the names.)  Demanding that a concrete class be const is a larger burden than in C++ since there is no workaround.

That's why I feel that this is the biggest threat to the adaption of a const-correctness policy in large D programs.

You are basically saying don't use const unless you know all the implementation details about a class, and don't put const in Interface/abstract class, just in final concrete class.

As you point, casting away constness is not an option. You need a way out, otherwise const will just be used for trivial things.

> 
> > - Could you elaborate more on what mutable members would 
> > break/prevent, if used reasonably?
> 
> The idea is that "const" in D means that the compiler can guarantee that no side effects happen.  First, if you call a method several times, can the compiler eliminate the subsequent calls?
> 
> for(int i = 0; i != v.size(); i++)
>   cout << v[i];
> 
> The compiler has to call v.size() for every iteration in C++.  In this case, if both v.operator[](int) and v.size() are inlined and simple then the compiler (might) be able to check constness via data flow analysis. But if not, the compiler can't cache .size() because in C++ the const might be "logical".


Logical const is still const, as far has there is no visible (public) side effect on the object. The implementation is still bound to that contract. The result of .size() may still be cached.


> 
> More importantly, it goes back to the idea of "reentrant" code.  Locks exist to prevent race conditions -- which are due to side effects.  Thus, side effect free ("pure") functions can be called by multiple threads at the same time with no locking, and causing no possible problem, since the calls are guaranteed to have no effects.  But that's not the case for "logical" const, so in C++ "const" is useless for making this determination.
> 
> In D const is about guarantees regarding bits, bytes, synchronization, and side effects, whereas in C++ version is about telling another programmer that the object has "the same value" before and after a method call.
> 
> Both goals are useful to some degree, but Walter is betting (as I read it), that in the future, guarantees about side effects and so on are much more useful, especially when code is scaled up and threaded.
> 
> > - If I do need mutable members in a const method (for lazy evaluation, 
> > caching, counter), what should I do? Is there technique you can 
> > propose to escape it (e.g. a way I can externalize the mutable part 
> > (seems difficult because of the transitive nature of const) )?
> 
> Yes -- any data stored outside the class can be fiddled with.
> 
> int * GetValue(inout int key)
> {
>     static int serial = 1;
>     static int[int] map;
>     if (key == -1) {
>         key = ++ serial;
>         map[key] = 0;
>     }
>     return key in map;
> }
> 
> class SomeClass {
> public:
>     int serial = -1;
>     
>     int counter() const
>     {
>         int * p = GetValue(serial);
>         return ++*p;
>     }
> };
> 
> Kevin
> 


So, there a way around it. You can outsource the mutable part to a static/global.

This is a side effect. Why not allow a mutable private members, and keep those implementation details encapsulated within the class. This code is not more guaranteed to be "reentrant" that mutable one.

With const, you promise that the object that will exhibit to the outside world a const behavior. However, you cannot say that a const-call has no side effect at all. 

In other words, const does not mean pure, with or without mutable members.





More information about the Digitalmars-d mailing list