Fully transitive const is not necessary

Steven Schveighoffer schveiguy at yahoo.com
Thu Apr 3 10:32:42 PDT 2008


"Janice Caron" wrote
> On 03/04/2008, Steven Schveighoffer wrote:
>> Have you no imagination? :)
>
> Apparently.
>
> So to cut a long story short, you're saying that you can have a class
> in which a non-pure function caches a result (in a mutable variable),
> and in which the pure version of the same function doesn't cache the
> result.
>
> You might just as well say, you can have a class in which a non-const
> function caches a result, and in which the const version of the same
> function doesn't. What's the difference?

The difference is that things start breaking when they expect to receive a 
const calculator.  For example, if I have a function that looks like this:

int[] calculateSomeValues(const(Calculator) c);

written by some other developer who says "I won't be changing c, and c 
defines that f is const, so I'll declare that c is const".

And then I say "hey, why don't I add a caching feature to Calculator that 
speeds up the code tremendously", but now, since I didn't write 
calculateSomeValues, I cannot pass the caching version to it.  So what ends 
up happening is I'll create a globby so I can "work around" the const system 
and create faster executing code (the globby has a penalty in the AA lookup, 
but we're assuming that each call to f is much more expensive than that). 
The problem is that in this case, const gets in the way, and didn't help me 
at all.  Const is supposed to help multiple developers work together, not 
prevent them from doing so.

You could say "so pass the cache in with the calculator", which is fine, but 
then I'm losing the whole point of being able to group related objects 
together!  Not only that, but now caluclulateSomeValues has to know at least 
that I'm passing some mutable state to it, so it has knowledge of the 
implementation, which it shouldn't have to know.  Why not encapsulate the 
mutable state in with the argument?  All a mutable state says is to the 
compiler "this part is not part of the object, so ignore it for const 
purposes."  That's all.  Think of it as an extra argument to all functions 
which take a class of that type, and that argument is implicitly passed to 
all member functions of the object, just like the 'this' pointer is.

>
> I guess what I'm trying to get at is that it is never /necessary/ to
> use mutable variables. There's always a way of rewriting the code so
> you don't need them. In this case:
>
>    class Calclulator
>    {
>        int config;
>        int f(int x) const { ... }
>        pure int f(int x) invariant { ... }
>    }
>
>    class CachingCalculator
>    {
>        Calculator calculator;
>        int[int] cache;
>        int f(int x)
>        {
>            auto p = x in cache;
>            if (p !is null) return *p;
>            int r = calculator.f(x);
>            cache[x] = r;
>            return r;
>        }
>    }
>
> You just have to wean yourself off the addiction to logical const.
> After you've gone cold turkey for a bit, you'll just stop wanting to
> use it.

I don't use const in most of my stuff, since 1) I only use Tango, and 2) all 
my D apps, and most of my other apps, are written only by me :)

The problem is that inevitably, I'll want to use someone else's library 
whose author decided to use const, and inevitably, they will have 
incorrectly implemented it, since they didn't think of all possible ways 
someone can use their lib.

-Steve 





More information about the Digitalmars-d mailing list