D2.0: an example of use-case for casting invariant away
Bruno Medeiros
brunodomedeiros+spam at com.gmail
Fri Jun 22 16:21:20 PDT 2007
Don Clugston wrote:
> Regan Heath wrote:
>> Walter Bright Wrote:
>>> Don Clugston wrote:
>>>> Walter Bright wrote:
>>>>> With D, you can cast away const-ness, that is legal. But if you
>>>>> subsequently modify the underlying data, that is undefined behavior.
>>>> It sounds that in D, it will be too easy to cast away constness
>>>> accidentally.
>>>> With C++, at least you can grep for const_cast and detect
>>>> potentially dangerous code, and you get a strong visual clue.
>>>> Suppose I've written a D function like this:
>>>>
>>>> void f(int *b, uint c)
>>>> {
>>>> // maybe I'm avoiding a compiler warning or something.
>>>> uint *d = cast(uint *)b;
>>>> d += c;
>>>> }
>>>>
>>>> Months later, I'm refactoring the code, and I convert the int *
>>>> parameter to an invariant, without recognising that it's changing
>>>> the value of b. Oops.
>>>>
>>>> C++'s const would catch this mistake, but if I understand correctly,
>>>> D will compile it without error. Suddenly the function has moved
>>>> into the realm of undefined behaviour.
>>>>
>>>> I hope I'm wrong. Or did I miss something?
>>> No, you're not missing something. It is a general problem with cast -
>>> cast is a blunt instrument which can easily hide problems.
>>
>> So.. we're going to have to put up with this potential nasty bug?
>>
>> What about a new cast which only removes 'const' and/or 'invariant and
>> prohibit normal cast from removing it.
>>
>> Perhaps calling it 'vary', eg.
>>
>> void f(const int *b, uint c)
>> {
>> int *d = vary() b;
>> }
>
> To avoid a new keyword...
>
> int* d = cast(break const) b;
>
> IMHO, we want something that looks really nasty.
New keyword? Why a new syntax a at all? This is the kind of stuff that
should be possible to do with D's (current or future) meta programming
capabilities. Here's a small proof of concept of what can currently be
done in D:
void main(char[][] args) {
const(char *) cfoo;
char* foo = unConst(cfoo);
writeln(typeid(typeof(unConst(cfoo))));
const(char **) cfoo2;
char** foo2 = unConst(cfoo2);
writeln(typeid(typeof(unConst(cfoo2))));
}
unConstType!(T) unConst(T)(T val) {
writeln(typeid(unConstType!(T)));
return cast(unConstType!(T)) val;
}
template unConstType(T : T*) {
pragma(msg, "*");
alias unConstType!(T)* unConstType;
}
template unConstType(T) {
alias typeof(T) unConstType;
}
It only unconstifies pointers (but that's easily extendable to other
native types), and the value returned cannot be used as an lvalue, but
in any case this is just to demonstrate that no new syntax should be
required.
The other case, a cast that only changes the core type, and not the
modifiers, i.e., something like:
const(char*) a = ...;
auto b = castBaseType!(int *)(a);
//typeof(b) == const(int *)
should also be possible to implement at the meta-programming level.
--
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
More information about the Digitalmars-d
mailing list