What's wrong with just a runtime-checked const?
Reiner Pope
reiner.pope at gmail.com
Sun Jul 16 14:53:31 PDT 2006
xs0 wrote:
> Reiner Pope wrote:
>>
>> 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:
>> [snip]
>> 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)?
>
> Well, I don't think you completely missed the point, but doing it would
> cause all sorts of issues:
> - where should the tag be placed? you can't put it inside the pointer,
> as there are no free bits; you also can't put it next to a pointer, as
> it would affect memory layout of structures (in particular, it would
> make debug-built and release-built code non-interoperable).
Yeah, I've thought about it a fair bit more and compatibility seems to
be the main issue. I did indeed mean that it would be stored next to the
pointer, but it does seem like that could cause problems with
interoperability. If all the info could be stored separately in a
bit-array managed by, say, the GC, then perhaps that would avoid the
issue of interoperability. But I haven't quite worked out how that would
be implemented yet...
> - it can still be trivially subverted - just cast to int/long and back
I presume this point leads on from the above, where you assumed that the
bit was stored *in* the pointer. So that's a null issue, since it
clearly isn't.
> - you can't just check at the beginning of a function
I don't understand your reason for this, but when I started writing down
the details more specifically, I realised that the advantage of runtime
const checking is a *huge* increase in flexibility, and having to say at
compile-time whether a function is const or not removes that flexibility
in my mind.
> - you can get the pointer in the middle of it; you can also get the
> pointer in _another_ function (from a global or in a multi-threaded
> program); checking at every access would be too expensive, I think,
> even for a debug build
I don't know how expensive it would be. Considering that all it is is
assert(!isConst);
that operation doesn't seem too hard. And of course, the compiler is
free to optimize away duplicate versions of it, like this:
_member = 4;
_member = 3;
Obviously there's no need to check isConst before the second assignment.
And on the issue of the pointer suddenly changing in the middle of the
function: well, it's actually not an issue, because I worked out that
it's best for the function to have a local copy of the isConst variable,
which means no other resources can change it (other than a malicious
hacker with pointers). This is also conceptually right, because it
doesn't make sense to give a function a certain level of modification
access and then change it while it is running.
However, I think now that checking at every access is the only flexible
way to manage const.
In my view, we either need runtime-checked const or nothing. Consider
this, and tell me how we can avoid excess dup calls if we use C++-style
const-checking:
class foo {
private char[] _name;
public const char[] getName()
{
return _name;
}
...
}
...
Import std.string;
foo f;
/*const*/ char[] name = f.getName();
char[] name_m = tolower(name);
// Can we modify name_m? Better dup it, just to make sure
name_m = name_m.dup();
With runtime const checking, we could fix that, though, by also getting
a bool variable back from tolower() which says whether it returned the
original string or a copy. Quite simply, compile-time const won't let
you do that, so you will actually produce *slower* code.
If you're interested, I'm trying to come up with a draft which has the
actual details, jut so it gives a more solid ground for discussion. My
problem at the moment is just what we mentioned earlier: operability
between debug and release builds. I suggested that each function should
be passed, behind the scenes, the relevant isConst variable, but that's
not compatible with release builds. I then thought that you could have
two copies of a function: one for const variables and one for non-const
variables. The correct one would be chosen at runtime, and external
packages would always choose the one for non-const variables (which is a
copy of the one for const variables, but with checking turned off). This
effectively duplicates the amount of machine code generated by the
compiler, but I am convinced that a solution like I propose is much
better than a simple static checking scheme for the flexibility reason I
mentioned above.
Reiner
More information about the Digitalmars-d-learn
mailing list