What's wrong with just a runtime-checked const?

Reiner Pope reiner.pope at gmail.com
Sat Jul 15 02:05:30 PDT 2006


Disclaimer: my background is a small amount of Java and C#, so perhaps I 
  am completely confusing the issue because of practically no C++ 
experience. Please tell me if that's the case.

Walter seems to have two main objections to a C++-style const:
1. it can be subverted with a const_cast, removing any guarantees about it.
2. it is hard to implement, but this doesn't seem to concern him as much 
as the former.

People have expressed a desire for const especially to ensure the 
Copy-on-Write idiom, and to make libraries more robust.

Wouldn't a runtime const check be much more flexible than a compile-time 
check? Const-safeness is fundamentally a correctness-checking feature, 
just like unit tests, so why not make it operate exactly like unit 
tests? I'm thinking of something like array bounds checking:

> If an index is out of bounds, an ArrayBoundsError exception is raised if detected at runtime, and an error if detected at compile time. A program may not rely on array bounds checking happening

and also:

> Implementation Note: Compilers should attempt to detect array bounds errors at compile time, for example:

...

> Insertion of array bounds checking code at runtime should be turned on and off with a compile time switch.

This would work in const this way: everything with pointer semantics 
(classes, arrays, actual pointers) has a hidden (*) field called 
isConst. This field is stored with the pointer, not the data, so it is 
always passed by value, just like arrays. The compiler inserts the 
following code into the precondition of every function that could cause 
a mutation:

    assert(!isConst, "Mutation of a const variable detected");
    /* Of course, since isConst is hidden, only the compiler has access 
to it, but you get the idea */

This then behaves like a unit-test, so it is removed for a release 
version, avoiding the slow-down and extra memory required. And since it 
is a field, not a type modifier, you don't need to go through your code 
and insert a whole lot of const's everywhere, because the compiler 
doesn't need to PROVE it is const-correct -- that's what unit-testing 
helps with.

Let's give some examples:

   class Foo
   {
     private char[] bar;
     const char[] getCoWBar() // The const tells the compiler to set the 
isConst field in the pointer to true
     {
       return bar;
     }

     char[] getNonCoWBar()
     {
       return bar;
     }
   }
   ...
   Foo foo;
   char[] a = foo.getCoWBar(); // OK, even though getCoWBar is const and 
a isn't
   a[0] = 'a'; // Error -- compile-time if the compiler is smart enough,
otherwise runtime
   a = a.dup; // OK
   a[0] = 'a'; // OK, because we duplicate it.
   a = getNonCoWBar(); // OK
   a[0] = 'a'; // OK -- it isn't const

In this, the only way to get a non-const pointer from a const pointer is 
by duplicating it. This makes data that can never change as simple as 
never having a non-const pointer to it:

    const char[] foo = "bar"; // OK
    char[] a = foo; // OK
    a[0] = 'a'; // Error

The even better thing about this is that most code doesn't need to have 
const-correctness in mind when writing it, and it shouldn't break 
existing code, because the only code that will break is code that is 
buggy code anyway.

Am I completely missing the point?
Will it cause memory/speed issues (keeping in mind that it's only for 
debug builds)?

* The field is hidden because it can't be safely used by the code as it 
is left out in a release build.



More information about the Digitalmars-d-learn mailing list