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