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